From 3c247355814f6a6e8d1d8f8984422c7488e43aa6 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 17 Jul 2024 21:22:55 +0200 Subject: [PATCH 01/99] chore: revisit staking flow --- operate/constants.py | 2 +- operate/services/manage.py | 142 +++++++++++++++++--------- operate/services/protocol.py | 192 +++++++++++++++++------------------ operate/services/service.py | 5 +- operate/types.py | 13 +-- 5 files changed, 202 insertions(+), 152 deletions(-) diff --git a/operate/constants.py b/operate/constants.py index 6136f15c2..8af868559 100644 --- a/operate/constants.py +++ b/operate/constants.py @@ -33,5 +33,5 @@ SERVICE_YAML = "service.yaml" ON_CHAIN_INTERACT_TIMEOUT = 120.0 -ON_CHAIN_INTERACT_RETRIES = 40.0 +ON_CHAIN_INTERACT_RETRIES = 40 ON_CHAIN_INTERACT_SLEEP = 3.0 diff --git a/operate/services/manage.py b/operate/services/manage.py index 927fff7cc..f27bbccd5 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -28,6 +28,7 @@ from pathlib import Path import aiohttp # type: ignore +import requests from aea.helpers.base import IPFSHash from aea.helpers.logging import setup_logger from autonomy.chain.base import registry_contracts @@ -39,6 +40,7 @@ from operate.services.service import ( DELETE_PREFIX, Deployment, + NON_EXISTENT_TOKEN, OnChainData, OnChainState, OnChainUserParams, @@ -60,6 +62,8 @@ DOCKER_COMPOSE_YAML = "docker-compose.yaml" SERVICE_YAML = "service.yaml" HTTP_OK = 200 +IPFS_GATEWAY = "https://gateway.autonolas.tech/ipfs/" +URI_HASH_POSITION = 7 async def check_service_health() -> bool: @@ -180,6 +184,36 @@ def load_or_create( return service + def _get_on_chain_state(self, service: Service) -> OnChainState: + if service.chain_data.token == NON_EXISTENT_TOKEN: + service_state = OnChainState.NON_EXISTENT + service.chain_data.on_chain_state = service_state + service.store() + return service_state + + sftxb = self.get_eth_safe_tx_builder(service=service) + info = sftxb.info(token_id=service.chain_data.token) + service_state = OnChainState(info["service_state"]) + service.chain_data.on_chain_state = service_state + service.store() + return service_state + + + def _get_on_chain_hash(self, service: Service) -> t.Optional[str]: + if service.chain_data.token == NON_EXISTENT_TOKEN: + return None + + sftxb = self.get_eth_safe_tx_builder(service=service) + info = sftxb.info(token_id=service.chain_data.token) + config_hash = info["config_hash"] + res = requests.get(f"{IPFS_GATEWAY}f01701220{config_hash}", timeout=30) + if res.status_code == 200: + return res.json().get("code_uri", "")[URI_HASH_POSITION:] + raise ValueError( + f"Something went wrong while trying to get the code uri from IPFS: {res}" + ) + + def deploy_service_onchain( # pylint: disable=too-many-statements self, hash: str, @@ -219,13 +253,13 @@ def deploy_service_onchain( # pylint: disable=too-many-statements if user_params.use_staking: self.logger.info("Checking staking compatibility") if service.chain_data.on_chain_state in ( - OnChainState.NOTMINTED, - OnChainState.MINTED, + OnChainState.NON_EXISTENT, + OnChainState.PRE_REGISTRATION, ): required_olas = ( user_params.olas_cost_of_bond + user_params.olas_required_to_stake ) - elif service.chain_data.on_chain_state == OnChainState.ACTIVATED: + elif service.chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: required_olas = user_params.olas_required_to_stake else: required_olas = 0 @@ -244,7 +278,7 @@ def deploy_service_onchain( # pylint: disable=too-many-statements f"required olas: {required_olas}; your balance {balance}" ) - if service.chain_data.on_chain_state == OnChainState.NOTMINTED: + if service.chain_data.on_chain_state == OnChainState.NON_EXISTENT: self.logger.info("Minting service") service.chain_data.token = t.cast( int, @@ -267,13 +301,13 @@ def deploy_service_onchain( # pylint: disable=too-many-statements ), ).get("token"), ) - service.chain_data.on_chain_state = OnChainState.MINTED + service.chain_data.on_chain_state = OnChainState.PRE_REGISTRATION service.store() info = ocm.info(token_id=service.chain_data.token) service.chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.on_chain_state == OnChainState.MINTED: + if service.chain_data.on_chain_state == OnChainState.PRE_REGISTRATION: self.logger.info("Activating service") ocm.activate( service_id=service.chain_data.token, @@ -283,13 +317,13 @@ def deploy_service_onchain( # pylint: disable=too-many-statements else None ), ) - service.chain_data.on_chain_state = OnChainState.ACTIVATED + service.chain_data.on_chain_state = OnChainState.ACTIVE_REGISTRATION service.store() info = ocm.info(token_id=service.chain_data.token) service.chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.on_chain_state == OnChainState.ACTIVATED: + if service.chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: self.logger.info("Registering service") ocm.register( service_id=service.chain_data.token, @@ -301,13 +335,13 @@ def deploy_service_onchain( # pylint: disable=too-many-statements else None ), ) - service.chain_data.on_chain_state = OnChainState.REGISTERED + service.chain_data.on_chain_state = OnChainState.FINISHED_REGISTRATION service.store() info = ocm.info(token_id=service.chain_data.token) service.chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.on_chain_state == OnChainState.REGISTERED: + if service.chain_data.on_chain_state == OnChainState.FINISHED_REGISTRATION: self.logger.info("Deploying service") ocm.deploy( service_id=service.chain_data.token, @@ -335,7 +369,6 @@ def deploy_service_onchain( # pylint: disable=too-many-statements def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too-many-locals self, hash: str, - update: bool = False, ) -> None: """ Deploy as service on-chain @@ -343,6 +376,8 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too :param hash: Service hash :param update: Update the existing deployment """ + self.logger.info("DEPLOY SERVICE ONCHAIN FROM SAFE ====================") + self.logger.info("Loading service") service = self.load_or_create(hash=hash) user_params = service.chain_data.user_params @@ -350,6 +385,10 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too instances = [key.address for key in keys] wallet = self.wallet_manager.load(service.ledger_config.type) sftxb = self.get_eth_safe_tx_builder(service=service) + + + + if user_params.use_staking and not sftxb.staking_slots_available( staking_contract=STAKING[service.ledger_config.chain] ): @@ -367,13 +406,13 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too if user_params.use_staking: self.logger.info("Checking staking compatibility") if service.chain_data.on_chain_state in ( - OnChainState.NOTMINTED, - OnChainState.MINTED, + OnChainState.NON_EXISTENT, + OnChainState.PRE_REGISTRATION, ): required_olas = ( user_params.olas_cost_of_bond + user_params.olas_required_to_stake ) - elif service.chain_data.on_chain_state == OnChainState.ACTIVATED: + elif service.chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: required_olas = user_params.olas_required_to_stake else: required_olas = 0 @@ -392,8 +431,22 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too f"address: {wallet.safe}; required olas: {required_olas}; your balance: {balance}" ) - if service.chain_data.on_chain_state == OnChainState.NOTMINTED: - self.logger.info("Minting service") + + + + on_chain_hash = self._get_on_chain_hash(service) + is_first_mint = self._get_on_chain_state(service) == OnChainState.NON_EXISTENT + is_update = (not is_first_mint) and on_chain_hash and (on_chain_hash != service.hash) + + self.logger.info(f"{on_chain_hash=}") + self.logger.info(f"{is_first_mint=}") + self.logger.info(f"{is_update=}") + + if is_update: + #TERMINATE SERVICE + + if is_first_mint or (is_update and self._get_on_chain_state(service) == OnChainState.PRE_REGISTRATION): + self.logger.info("Minting the on-chain service") receipt = ( sftxb.new_tx() .add( @@ -408,7 +461,7 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too ), threshold=user_params.threshold, nft=IPFSHash(user_params.nft), - update_token=service.chain_data.token if update else None, + update_token=service.chain_data.token if is_update else None, token=( OLAS[service.ledger_config.chain] if user_params.use_staking @@ -428,13 +481,10 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too ).get("events"), ) service.chain_data.token = event_data["args"]["serviceId"] - service.chain_data.on_chain_state = OnChainState.MINTED + service.chain_data.on_chain_state = OnChainState.PRE_REGISTRATION service.store() - info = sftxb.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) - - if service.chain_data.on_chain_state == OnChainState.MINTED: + if self._get_on_chain_state(service) == OnChainState.PRE_REGISTRATION: cost_of_bond = user_params.cost_of_bond if user_params.use_staking: token_utility = "0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8" # nosec @@ -480,13 +530,10 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too cost_of_bond=cost_of_bond, ) ).settle() - service.chain_data.on_chain_state = OnChainState.ACTIVATED + service.chain_data.on_chain_state = OnChainState.ACTIVE_REGISTRATION service.store() - info = sftxb.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) - - if service.chain_data.on_chain_state == OnChainState.ACTIVATED: + if self._get_on_chain_state(service) == OnChainState.ACTIVE_REGISTRATION: cost_of_bond = user_params.cost_of_bond if user_params.use_staking: token_utility = "0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8" # nosec @@ -536,18 +583,15 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too cost_of_bond=cost_of_bond, ) ).settle() - service.chain_data.on_chain_state = OnChainState.REGISTERED + service.chain_data.on_chain_state = OnChainState.FINISHED_REGISTRATION service.store() - info = sftxb.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) - - if service.chain_data.on_chain_state == OnChainState.REGISTERED: + if self._get_on_chain_state(service) == OnChainState.FINISHED_REGISTRATION: self.logger.info("Deploying service") sftxb.new_tx().add( sftxb.get_deploy_data( service_id=service.chain_data.token, - reuse_multisig=update, + reuse_multisig=is_update, ) ).settle() service.chain_data.on_chain_state = OnChainState.DEPLOYED @@ -588,7 +632,7 @@ def terminate_service_on_chain(self, hash: str) -> None: else None ), ) - service.chain_data.on_chain_state = OnChainState.TERMINATED + service.chain_data.on_chain_state = OnChainState.TERMINATED_BONDED service.store() def terminate_service_on_chain_from_safe(self, hash: str) -> None: @@ -612,7 +656,7 @@ def terminate_service_on_chain_from_safe(self, hash: str) -> None: service_id=service.chain_data.token, ) ).settle() - service.chain_data.on_chain_state = OnChainState.TERMINATED + service.chain_data.on_chain_state = OnChainState.TERMINATED_BONDED service.store() def unbond_service_on_chain(self, hash: str) -> None: @@ -626,7 +670,7 @@ def unbond_service_on_chain(self, hash: str) -> None: info = ocm.info(token_id=service.chain_data.token) service.chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.on_chain_state != OnChainState.TERMINATED: + if service.chain_data.on_chain_state != OnChainState.TERMINATED_BONDED: self.logger.info("Cannot unbond service") return @@ -653,7 +697,7 @@ def unbond_service_on_chain_from_safe(self, hash: str) -> None: info = sftxb.info(token_id=service.chain_data.token) service.chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.on_chain_state != OnChainState.TERMINATED: + if service.chain_data.on_chain_state != OnChainState.TERMINATED_BONDED: self.logger.info("Cannot unbond service") return @@ -663,7 +707,7 @@ def unbond_service_on_chain_from_safe(self, hash: str) -> None: service_id=service.chain_data.token, ) ).settle() - service.chain_data.on_chain_state = OnChainState.TERMINATED + service.chain_data.on_chain_state = OnChainState.TERMINATED_BONDED service.store() def stake_service_on_chain(self, hash: str) -> None: @@ -984,6 +1028,8 @@ def update_service( from_safe: bool = True, # pylint: disable=unused-argument ) -> Service: """Update a service.""" + + self.logger.info("-----Entering update service on-chain-----") old_service = self.load_or_create( hash=old_hash, ) @@ -1016,19 +1062,21 @@ def update_service( # owner, *_ = old_service.chain_data.instances # noqa: E800 # if from_safe: # noqa: E800 # sftx = self.get_eth_safe_tx_builder(service=old_service) # noqa: E800 - # sftx.new_tx().add( # noqa: E800 - # sftx.get_swap_data( # noqa: E800 - # service_id=old_service.chain_data.token, # noqa: E800 - # multisig=old_service.chain_data.multisig, # noqa: E800 - # owner_key=str(self.keys_manager.get(key=owner).private_key), # noqa: E800 - # ) # noqa: E800 - # ).settle() # noqa: E800 + # sftx.swap( # noqa: E800 + # service_id=old_service.chain_data.token, # noqa: E800 + # multisig=old_service.chain_data.multisig, # noqa: E800 + # owner_key=str( + # self.keys_manager.get(key=owner).private_key + # ), # noqa: E800 + # ) # noqa: E800 # else: # noqa: E800 # ocm = self.get_on_chain_manager(service=old_service) # noqa: E800 # ocm.swap( # noqa: E800 # service_id=old_service.chain_data.token, # noqa: E800 # multisig=old_service.chain_data.multisig, # noqa: E800 - # owner_key=str(self.keys_manager.get(key=owner).private_key), # noqa: E800 + # owner_key=str( + # self.keys_manager.get(key=owner).private_key + # ), # noqa: E800 # ) # noqa: E800 new_service = self.load_or_create( @@ -1040,7 +1088,7 @@ def update_service( new_service.keys = old_service.keys new_service.chain_data = old_service.chain_data new_service.ledger_config = old_service.ledger_config - new_service.chain_data.on_chain_state = OnChainState.NOTMINTED + new_service.chain_data.on_chain_state = OnChainState.NON_EXISTENT new_service.store() # The following logging has been added to identify OS issues when diff --git a/operate/services/protocol.py b/operate/services/protocol.py index f6d8acf46..b79522533 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -521,6 +521,102 @@ def info(self, token_id: int) -> t.Dict: instances=instances, ) + def swap( # pylint: disable=too-many-arguments,too-many-locals + self, + service_id: int, + multisig: str, + owner_key: str, + ) -> None: + """Swap safe owner.""" + logging.info(f"Swapping safe for service {service_id} [{multisig}]...") + self._patch() + manager = ServiceManager( + service_id=service_id, + chain_type=self.chain_type, + key=self.wallet.key_path, + password=self.wallet.password, + timeout=ON_CHAIN_INTERACT_TIMEOUT, + retries=ON_CHAIN_INTERACT_RETRIES, + sleep=ON_CHAIN_INTERACT_SLEEP, + ) + with tempfile.TemporaryDirectory() as temp_dir: + key_file = Path(temp_dir, "key.txt") + key_file.write_text(owner_key, encoding="utf-8") + owner_crypto = EthereumCrypto(private_key_path=str(key_file)) + owner_cryptos: t.List[EthereumCrypto] = [owner_crypto] + owners = [ + manager.ledger_api.api.to_checksum_address(owner_crypto.address) + for owner_crypto in owner_cryptos + ] + owner_to_swap = owners[0] + multisend_txs = [] + txd = registry_contracts.gnosis_safe.get_swap_owner_data( + ledger_api=manager.ledger_api, + contract_address=multisig, + old_owner=manager.ledger_api.api.to_checksum_address(owner_to_swap), + new_owner=manager.ledger_api.api.to_checksum_address( + manager.crypto.address + ), + ).get("data") + multisend_txs.append( + { + "operation": MultiSendOperation.CALL, + "to": multisig, + "value": 0, + "data": HexBytes(txd[2:]), + } + ) + multisend_txd = registry_contracts.multisend.get_tx_data( # type: ignore + ledger_api=manager.ledger_api, + contract_address=ContractConfigs.multisend.contracts[self.chain_type], + multi_send_txs=multisend_txs, + ).get("data") + multisend_data = bytes.fromhex(multisend_txd[2:]) + safe_tx_hash = registry_contracts.gnosis_safe.get_raw_safe_transaction_hash( + ledger_api=manager.ledger_api, + contract_address=multisig, + to_address=ContractConfigs.multisend.contracts[self.chain_type], + value=0, + data=multisend_data, + safe_tx_gas=0, + operation=SafeOperation.DELEGATE_CALL.value, + ).get("tx_hash")[2:] + payload_data = hash_payload_to_hex( + safe_tx_hash=safe_tx_hash, + ether_value=0, + safe_tx_gas=0, + to_address=ContractConfigs.multisend.contracts[self.chain_type], + data=multisend_data, + ) + tx_params = skill_input_hex_to_payload(payload=payload_data) + safe_tx_bytes = binascii.unhexlify(tx_params["safe_tx_hash"]) + owner_to_signature = {} + for owner_crypto in owner_cryptos: + signature = owner_crypto.sign_message( + message=safe_tx_bytes, + is_deprecated_mode=True, + ) + owner_to_signature[ + manager.ledger_api.api.to_checksum_address(owner_crypto.address) + ] = signature[2:] + tx = registry_contracts.gnosis_safe.get_raw_safe_transaction( + ledger_api=manager.ledger_api, + contract_address=multisig, + sender_address=owner_crypto.address, + owners=tuple(owners), # type: ignore + to_address=tx_params["to_address"], + value=tx_params["ether_value"], + data=tx_params["data"], + safe_tx_gas=tx_params["safe_tx_gas"], + signatures_by_owner=owner_to_signature, + operation=SafeOperation.DELEGATE_CALL.value, + ) + stx = owner_crypto.sign_transaction(tx) + tx_digest = manager.ledger_api.send_signed_transaction(stx) + receipt = manager.ledger_api.api.eth.wait_for_transaction_receipt(tx_digest) + if receipt["status"] != 1: + raise RuntimeError("Error swapping owners") + class OnChainManager(_ChainUtil): """On chain service management.""" @@ -657,102 +753,6 @@ def deploy( reuse_multisig=reuse_multisig, ) - def swap( # pylint: disable=too-many-arguments,too-many-locals - self, - service_id: int, - multisig: str, - owner_key: str, - ) -> None: - """Swap safe owner.""" - logging.info(f"Swapping safe for service {service_id} [{multisig}]...") - self._patch() - manager = ServiceManager( - service_id=service_id, - chain_type=self.chain_type, - key=self.wallet.key_path, - password=self.wallet.password, - timeout=ON_CHAIN_INTERACT_TIMEOUT, - retries=ON_CHAIN_INTERACT_RETRIES, - sleep=ON_CHAIN_INTERACT_SLEEP, - ) - with tempfile.TemporaryDirectory() as temp_dir: - key_file = Path(temp_dir, "key.txt") - key_file.write_text(owner_key, encoding="utf-8") - owner_crypto = EthereumCrypto(private_key_path=str(key_file)) - owner_cryptos: t.List[EthereumCrypto] = [owner_crypto] - owners = [ - manager.ledger_api.api.to_checksum_address(owner_crypto.address) - for owner_crypto in owner_cryptos - ] - owner_to_swap = owners[0] - multisend_txs = [] - txd = registry_contracts.gnosis_safe.get_swap_owner_data( - ledger_api=manager.ledger_api, - contract_address=multisig, - old_owner=manager.ledger_api.api.to_checksum_address(owner_to_swap), - new_owner=manager.ledger_api.api.to_checksum_address( - manager.crypto.address - ), - ).get("data") - multisend_txs.append( - { - "operation": MultiSendOperation.CALL, - "to": multisig, - "value": 0, - "data": HexBytes(txd[2:]), - } - ) - multisend_txd = registry_contracts.multisend.get_tx_data( # type: ignore - ledger_api=manager.ledger_api, - contract_address=ContractConfigs.multisend.contracts[self.chain_type], - multi_send_txs=multisend_txs, - ).get("data") - multisend_data = bytes.fromhex(multisend_txd[2:]) - safe_tx_hash = registry_contracts.gnosis_safe.get_raw_safe_transaction_hash( - ledger_api=manager.ledger_api, - contract_address=multisig, - to_address=ContractConfigs.multisend.contracts[self.chain_type], - value=0, - data=multisend_data, - safe_tx_gas=0, - operation=SafeOperation.DELEGATE_CALL.value, - ).get("tx_hash")[2:] - payload_data = hash_payload_to_hex( - safe_tx_hash=safe_tx_hash, - ether_value=0, - safe_tx_gas=0, - to_address=ContractConfigs.multisend.contracts[self.chain_type], - data=multisend_data, - ) - tx_params = skill_input_hex_to_payload(payload=payload_data) - safe_tx_bytes = binascii.unhexlify(tx_params["safe_tx_hash"]) - owner_to_signature = {} - for owner_crypto in owner_cryptos: - signature = owner_crypto.sign_message( - message=safe_tx_bytes, - is_deprecated_mode=True, - ) - owner_to_signature[ - manager.ledger_api.api.to_checksum_address(owner_crypto.address) - ] = signature[2:] - tx = registry_contracts.gnosis_safe.get_raw_safe_transaction( - ledger_api=manager.ledger_api, - contract_address=multisig, - sender_address=owner_crypto.address, - owners=tuple(owners), # type: ignore - to_address=tx_params["to_address"], - value=tx_params["ether_value"], - data=tx_params["data"], - safe_tx_gas=tx_params["safe_tx_gas"], - signatures_by_owner=owner_to_signature, - operation=SafeOperation.DELEGATE_CALL.value, - ) - stx = owner_crypto.sign_transaction(tx) - tx_digest = manager.ledger_api.send_signed_transaction(stx) - receipt = manager.ledger_api.api.eth.wait_for_transaction_receipt(tx_digest) - if receipt["status"] != 1: - raise RuntimeError("Error swapping owners") - def terminate(self, service_id: int, token: t.Optional[str] = None) -> None: """Terminate service.""" logging.info(f"Terminating service {service_id}...") diff --git a/operate/services/service.py b/operate/services/service.py index 193ba7561..67121bb44 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -86,6 +86,7 @@ # pylint: disable=no-member,redefined-builtin,too-many-instance-attributes DUMMY_MULTISIG = "0xm" +NON_EXISTENT_TOKEN = -1 def mkdirs(build_dir: Path) -> None: @@ -690,10 +691,10 @@ def new( ), chain_data=OnChainData( instances=[], - token=-1, + token=NON_EXISTENT_TOKEN, multisig=DUMMY_MULTISIG, staked=False, - on_chain_state=OnChainState.NOTMINTED, + on_chain_state=OnChainState.NON_EXISTENT, user_params=on_chain_user_params, ), path=service_path.parent, diff --git a/operate/types.py b/operate/types.py index 29f83ec71..1babb5f82 100644 --- a/operate/types.py +++ b/operate/types.py @@ -130,16 +130,17 @@ class DeploymentStatus(enum.IntEnum): DELETED = 6 +# TODO defined in aea.chain.base.OnChainState class OnChainState(enum.IntEnum): """On-chain state.""" - NOTMINTED = 0 - MINTED = 1 - ACTIVATED = 2 - REGISTERED = 3 + NON_EXISTENT = 0 + PRE_REGISTRATION = 1 + ACTIVE_REGISTRATION = 2 + FINISHED_REGISTRATION = 3 DEPLOYED = 4 - TERMINATED = 5 - UNBONDED = 6 + TERMINATED_BONDED = 5 + UNBONDED = 6 # TODO this is not an on-chain state https://github.com/valory-xyz/autonolas-registries/blob/main/contracts/ServiceRegistryL2.sol class ContractAddresses(TypedDict): From e294ad0a0c940b05da93e308c5e71d3bd1b98996 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 17 Jul 2024 22:56:28 +0200 Subject: [PATCH 02/99] chore: updates --- operate/services/manage.py | 93 +++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 51 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index f27bbccd5..78f654515 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -386,9 +386,6 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too wallet = self.wallet_manager.load(service.ledger_config.type) sftxb = self.get_eth_safe_tx_builder(service=service) - - - if user_params.use_staking and not sftxb.staking_slots_available( staking_contract=STAKING[service.ledger_config.chain] ): @@ -432,21 +429,23 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too ) - - on_chain_hash = self._get_on_chain_hash(service) is_first_mint = self._get_on_chain_state(service) == OnChainState.NON_EXISTENT - is_update = (not is_first_mint) and on_chain_hash and (on_chain_hash != service.hash) + is_update = (not is_first_mint) and (on_chain_hash is not None) and (on_chain_hash != service.hash) self.logger.info(f"{on_chain_hash=}") self.logger.info(f"{is_first_mint=}") self.logger.info(f"{is_update=}") if is_update: - #TERMINATE SERVICE + self.terminate_service_on_chain_from_safe(hash=hash) if is_first_mint or (is_update and self._get_on_chain_state(service) == OnChainState.PRE_REGISTRATION): - self.logger.info("Minting the on-chain service") + if not is_update: + self.logger.info("Minting the on-chain service") + else: + self.logger.info("Updating the on-chain service") + receipt = ( sftxb.new_tx() .add( @@ -597,13 +596,15 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too service.chain_data.on_chain_state = OnChainState.DEPLOYED service.store() + + # Update local Service info = sftxb.info(token_id=service.chain_data.token) service.chain_data = OnChainData( token=service.chain_data.token, instances=info["instances"], multisig=info["multisig"], staked=False, - on_chain_state=service.chain_data.on_chain_state, + on_chain_state=OnChainState(info["service_state"]), user_params=service.chain_data.user_params, ) service.store() @@ -641,23 +642,44 @@ def terminate_service_on_chain_from_safe(self, hash: str) -> None: :param hash: Service hash """ + service = self.load_or_create(hash=hash) sftxb = self.get_eth_safe_tx_builder(service=service) info = sftxb.info(token_id=service.chain_data.token) service.chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.on_chain_state != OnChainState.DEPLOYED: - self.logger.info("Cannot terminate service") + if service.chain_data.user_params.use_staking and not self._can_unstake_service(hash=hash): return - self.logger.info("Terminating service") - sftxb.new_tx().add( - sftxb.get_terminate_data( - service_id=service.chain_data.token, - ) - ).settle() - service.chain_data.on_chain_state = OnChainState.TERMINATED_BONDED - service.store() + self.unstake_service_on_chain(hash=hash) + + if self._get_on_chain_state(service) in (OnChainState.ACTIVE_REGISTRATION, OnChainState.FINISHED_REGISTRATION, OnChainState.DEPLOYED): + self.logger.info("Terminating service") + sftxb.new_tx().add( + sftxb.get_terminate_data( + service_id=service.chain_data.token, + ) + ).settle() + + if self._get_on_chain_state(service) == OnChainState.TERMINATED_BONDED: + self.logger.info("Unbonding service") + sftxb.new_tx().add( + sftxb.get_unbond_data( + service_id=service.chain_data.token, + ) + ).settle() + + + if [[ "$current_safe_owners" == "['$agent_address']" ]]: + sftx = self.get_eth_safe_tx_builder(service=old_service) # noqa: E800 + sftx.swap( # noqa: E800 + service_id=old_service.chain_data.token, # noqa: E800 + multisig=old_service.chain_data.multisig, # noqa: E800 + owner_key=str( + self.keys_manager.get(key=owner).private_key + ), # noqa: E800 + ) # noqa: E800 + def unbond_service_on_chain(self, hash: str) -> None: """ @@ -686,30 +708,6 @@ def unbond_service_on_chain(self, hash: str) -> None: service.chain_data.on_chain_state = OnChainState.UNBONDED service.store() - def unbond_service_on_chain_from_safe(self, hash: str) -> None: - """ - Terminate service on-chain - - :param hash: Service hash - """ - service = self.load_or_create(hash=hash) - sftxb = self.get_eth_safe_tx_builder(service=service) - info = sftxb.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) - - if service.chain_data.on_chain_state != OnChainState.TERMINATED_BONDED: - self.logger.info("Cannot unbond service") - return - - self.logger.info("Unbonding service") - sftxb.new_tx().add( - sftxb.get_unbond_data( - service_id=service.chain_data.token, - ) - ).settle() - service.chain_data.on_chain_state = OnChainState.TERMINATED_BONDED - service.store() - def stake_service_on_chain(self, hash: str) -> None: """ Stake service on-chain @@ -1061,14 +1059,7 @@ def update_service( # owner, *_ = old_service.chain_data.instances # noqa: E800 # if from_safe: # noqa: E800 - # sftx = self.get_eth_safe_tx_builder(service=old_service) # noqa: E800 - # sftx.swap( # noqa: E800 - # service_id=old_service.chain_data.token, # noqa: E800 - # multisig=old_service.chain_data.multisig, # noqa: E800 - # owner_key=str( - # self.keys_manager.get(key=owner).private_key - # ), # noqa: E800 - # ) # noqa: E800 + # else: # noqa: E800 # ocm = self.get_on_chain_manager(service=old_service) # noqa: E800 # ocm.swap( # noqa: E800 From 4184f208a0e9344c127d9ba0929a18f998c5530a Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Fri, 19 Jul 2024 15:19:11 +0200 Subject: [PATCH 03/99] [no ci] chore: update --- operate/services/manage.py | 1 - 1 file changed, 1 deletion(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 78f654515..e8d452728 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -374,7 +374,6 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too Deploy as service on-chain :param hash: Service hash - :param update: Update the existing deployment """ self.logger.info("DEPLOY SERVICE ONCHAIN FROM SAFE ====================") From e3cb6c0bbece2be6272815de9905ba854a658f80 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Fri, 26 Jul 2024 13:21:27 +0200 Subject: [PATCH 04/99] chore: bump framework --- poetry.lock | 889 +++++++++++++++++++++++-------------------------- pyproject.toml | 12 +- 2 files changed, 430 insertions(+), 471 deletions(-) diff --git a/poetry.lock b/poetry.lock index f98e0f9a6..fd3b19a72 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiohttp" version = "3.9.5" description = "Async http client/server framework (asyncio)" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -101,7 +100,6 @@ speedups = ["Brotli", "aiodns", "brotlicffi"] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -116,7 +114,6 @@ frozenlist = ">=1.1.0" name = "altgraph" version = "0.17.4" description = "Python graph (network) package" -category = "main" optional = false python-versions = "*" files = [ @@ -128,7 +125,6 @@ files = [ name = "annotated-types" version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -140,7 +136,6 @@ files = [ name = "anyio" version = "4.4.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -163,7 +158,6 @@ trio = ["trio (>=0.23)"] name = "asn1crypto" version = "1.5.1" description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" -category = "main" optional = false python-versions = "*" files = [ @@ -175,7 +169,6 @@ files = [ name = "async-timeout" version = "4.0.3" description = "Timeout context manager for asyncio programs" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -187,7 +180,6 @@ files = [ name = "attrs" version = "23.2.0" description = "Classes Without Boilerplate" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -207,7 +199,6 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p name = "backoff" version = "2.2.1" description = "Function decoration for backoff and retry" -category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -219,7 +210,6 @@ files = [ name = "base58" version = "2.1.1" description = "Base58 and Base58Check implementation." -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -232,39 +222,38 @@ tests = ["PyHamcrest (>=2.0.2)", "mypy", "pytest (>=4.6)", "pytest-benchmark", " [[package]] name = "bcrypt" -version = "4.1.3" +version = "4.2.0" description = "Modern password hashing for your software and your servers" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "bcrypt-4.1.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:48429c83292b57bf4af6ab75809f8f4daf52aa5d480632e53707805cc1ce9b74"}, - {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a8bea4c152b91fd8319fef4c6a790da5c07840421c2b785084989bf8bbb7455"}, - {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d3b317050a9a711a5c7214bf04e28333cf528e0ed0ec9a4e55ba628d0f07c1a"}, - {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:094fd31e08c2b102a14880ee5b3d09913ecf334cd604af27e1013c76831f7b05"}, - {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:4fb253d65da30d9269e0a6f4b0de32bd657a0208a6f4e43d3e645774fb5457f3"}, - {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:193bb49eeeb9c1e2db9ba65d09dc6384edd5608d9d672b4125e9320af9153a15"}, - {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:8cbb119267068c2581ae38790e0d1fbae65d0725247a930fc9900c285d95725d"}, - {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6cac78a8d42f9d120b3987f82252bdbeb7e6e900a5e1ba37f6be6fe4e3848286"}, - {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:01746eb2c4299dd0ae1670234bf77704f581dd72cc180f444bfe74eb80495b64"}, - {file = "bcrypt-4.1.3-cp37-abi3-win32.whl", hash = "sha256:037c5bf7c196a63dcce75545c8874610c600809d5d82c305dd327cd4969995bf"}, - {file = "bcrypt-4.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:8a893d192dfb7c8e883c4576813bf18bb9d59e2cfd88b68b725990f033f1b978"}, - {file = "bcrypt-4.1.3-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d4cf6ef1525f79255ef048b3489602868c47aea61f375377f0d00514fe4a78c"}, - {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5698ce5292a4e4b9e5861f7e53b1d89242ad39d54c3da451a93cac17b61921a"}, - {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec3c2e1ca3e5c4b9edb94290b356d082b721f3f50758bce7cce11d8a7c89ce84"}, - {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3a5be252fef513363fe281bafc596c31b552cf81d04c5085bc5dac29670faa08"}, - {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5f7cd3399fbc4ec290378b541b0cf3d4398e4737a65d0f938c7c0f9d5e686611"}, - {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:c4c8d9b3e97209dd7111bf726e79f638ad9224b4691d1c7cfefa571a09b1b2d6"}, - {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:31adb9cbb8737a581a843e13df22ffb7c84638342de3708a98d5c986770f2834"}, - {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:551b320396e1d05e49cc18dd77d970accd52b322441628aca04801bbd1d52a73"}, - {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6717543d2c110a155e6821ce5670c1f512f602eabb77dba95717ca76af79867d"}, - {file = "bcrypt-4.1.3-cp39-abi3-win32.whl", hash = "sha256:6004f5229b50f8493c49232b8e75726b568535fd300e5039e255d919fc3a07f2"}, - {file = "bcrypt-4.1.3-cp39-abi3-win_amd64.whl", hash = "sha256:2505b54afb074627111b5a8dc9b6ae69d0f01fea65c2fcaea403448c503d3991"}, - {file = "bcrypt-4.1.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:cb9c707c10bddaf9e5ba7cdb769f3e889e60b7d4fea22834b261f51ca2b89fed"}, - {file = "bcrypt-4.1.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9f8ea645eb94fb6e7bea0cf4ba121c07a3a182ac52876493870033141aa687bc"}, - {file = "bcrypt-4.1.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f44a97780677e7ac0ca393bd7982b19dbbd8d7228c1afe10b128fd9550eef5f1"}, - {file = "bcrypt-4.1.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d84702adb8f2798d813b17d8187d27076cca3cd52fe3686bb07a9083930ce650"}, - {file = "bcrypt-4.1.3.tar.gz", hash = "sha256:2ee15dd749f5952fe3f0430d0ff6b74082e159c50332a1413d51b5689cf06623"}, + {file = "bcrypt-4.2.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb"}, + {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00"}, + {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d"}, + {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291"}, + {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328"}, + {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7"}, + {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399"}, + {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060"}, + {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7"}, + {file = "bcrypt-4.2.0-cp37-abi3-win32.whl", hash = "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458"}, + {file = "bcrypt-4.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5"}, + {file = "bcrypt-4.2.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841"}, + {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68"}, + {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe"}, + {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2"}, + {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c"}, + {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae"}, + {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d"}, + {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e"}, + {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8"}, + {file = "bcrypt-4.2.0-cp39-abi3-win32.whl", hash = "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34"}, + {file = "bcrypt-4.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9"}, + {file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a"}, + {file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db"}, + {file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170"}, + {file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184"}, + {file = "bcrypt-4.2.0.tar.gz", hash = "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221"}, ] [package.extras] @@ -275,7 +264,6 @@ typecheck = ["mypy"] name = "bech32" version = "1.2.0" description = "Reference implementation for Bech32 and segwit addresses." -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -287,7 +275,6 @@ files = [ name = "bitarray" version = "2.9.2" description = "efficient arrays of booleans -- C extension" -category = "main" optional = false python-versions = "*" files = [ @@ -419,7 +406,6 @@ files = [ name = "certifi" version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -431,7 +417,6 @@ files = [ name = "cffi" version = "1.16.0" description = "Foreign Function Interface for Python calling C code." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -494,24 +479,107 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "2.1.1" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false -python-versions = ">=3.6.0" -files = [ - {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, - {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, +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.extras] -unicode-backport = ["unicodedata2"] - [[package]] name = "clea" version = "0.1.0rc4" description = "Framework for writing CLI application quickly" -category = "main" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -524,14 +592,13 @@ typing-extensions = ">=4.7.1,<5.0.0" [[package]] name = "click" -version = "8.0.2" +version = "8.1.7" description = "Composable command line interface toolkit" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "click-8.0.2-py3-none-any.whl", hash = "sha256:3fab8aeb8f15f5452ae7511ad448977b3417325bceddd53df87e0bb81f3a8cf8"}, - {file = "click-8.0.2.tar.gz", hash = "sha256:7027bc7bbafaab8b2c2816861d8eb372429ee3c02e193fc2f93d6c4ab9de49c5"}, + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [package.dependencies] @@ -541,7 +608,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "coincurve" version = "18.0.0" description = "Cross-platform Python CFFI bindings for libsecp256k1" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -597,7 +663,6 @@ cffi = ">=1.3.0" name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -609,7 +674,6 @@ files = [ name = "cosmpy" version = "0.9.2" description = "A library for interacting with the cosmos networks" -category = "main" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -630,64 +694,63 @@ requests = "*" [[package]] name = "coverage" -version = "7.5.4" +version = "7.6.0" description = "Code coverage measurement for Python" -category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99"}, - {file = "coverage-7.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47"}, - {file = "coverage-7.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2214ee920787d85db1b6a0bd9da5f8503ccc8fcd5814d90796c2f2493a2f4d2e"}, - {file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1137f46adb28e3813dec8c01fefadcb8c614f33576f672962e323b5128d9a68d"}, - {file = "coverage-7.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b385d49609f8e9efc885790a5a0e89f2e3ae042cdf12958b6034cc442de428d3"}, - {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b4a474f799456e0eb46d78ab07303286a84a3140e9700b9e154cfebc8f527016"}, - {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5cd64adedf3be66f8ccee418473c2916492d53cbafbfcff851cbec5a8454b136"}, - {file = "coverage-7.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9"}, - {file = "coverage-7.5.4-cp310-cp310-win32.whl", hash = "sha256:7076b4b3a5f6d2b5d7f1185fde25b1e54eb66e647a1dfef0e2c2bfaf9b4c88c8"}, - {file = "coverage-7.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f"}, - {file = "coverage-7.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5"}, - {file = "coverage-7.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba"}, - {file = "coverage-7.5.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b"}, - {file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d45d3cbd94159c468b9b8c5a556e3f6b81a8d1af2a92b77320e887c3e7a5d080"}, - {file = "coverage-7.5.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c"}, - {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7a892be37ca35eb5019ec85402c3371b0f7cda5ab5056023a7f13da0961e60da"}, - {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8192794d120167e2a64721d88dbd688584675e86e15d0569599257566dec9bf0"}, - {file = "coverage-7.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:820bc841faa502e727a48311948e0461132a9c8baa42f6b2b84a29ced24cc078"}, - {file = "coverage-7.5.4-cp311-cp311-win32.whl", hash = "sha256:6aae5cce399a0f065da65c7bb1e8abd5c7a3043da9dceb429ebe1b289bc07806"}, - {file = "coverage-7.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:d2e344d6adc8ef81c5a233d3a57b3c7d5181f40e79e05e1c143da143ccb6377d"}, - {file = "coverage-7.5.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:54317c2b806354cbb2dc7ac27e2b93f97096912cc16b18289c5d4e44fc663233"}, - {file = "coverage-7.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:042183de01f8b6d531e10c197f7f0315a61e8d805ab29c5f7b51a01d62782747"}, - {file = "coverage-7.5.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6bb74ed465d5fb204b2ec41d79bcd28afccf817de721e8a807d5141c3426638"}, - {file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3d45ff86efb129c599a3b287ae2e44c1e281ae0f9a9bad0edc202179bcc3a2e"}, - {file = "coverage-7.5.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5013ed890dc917cef2c9f765c4c6a8ae9df983cd60dbb635df8ed9f4ebc9f555"}, - {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1014fbf665fef86cdfd6cb5b7371496ce35e4d2a00cda501cf9f5b9e6fced69f"}, - {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3684bc2ff328f935981847082ba4fdc950d58906a40eafa93510d1b54c08a66c"}, - {file = "coverage-7.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805"}, - {file = "coverage-7.5.4-cp312-cp312-win32.whl", hash = "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b"}, - {file = "coverage-7.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7"}, - {file = "coverage-7.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdd31315fc20868c194130de9ee6bfd99755cc9565edff98ecc12585b90be882"}, - {file = "coverage-7.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d"}, - {file = "coverage-7.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d05c16cf4b4c2fc880cb12ba4c9b526e9e5d5bb1d81313d4d732a5b9fe2b9d53"}, - {file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5986ee7ea0795a4095ac4d113cbb3448601efca7f158ec7f7087a6c705304e4"}, - {file = "coverage-7.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df54843b88901fdc2f598ac06737f03d71168fd1175728054c8f5a2739ac3e4"}, - {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ab73b35e8d109bffbda9a3e91c64e29fe26e03e49addf5b43d85fc426dde11f9"}, - {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:aea072a941b033813f5e4814541fc265a5c12ed9720daef11ca516aeacd3bd7f"}, - {file = "coverage-7.5.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:16852febd96acd953b0d55fc842ce2dac1710f26729b31c80b940b9afcd9896f"}, - {file = "coverage-7.5.4-cp38-cp38-win32.whl", hash = "sha256:8f894208794b164e6bd4bba61fc98bf6b06be4d390cf2daacfa6eca0a6d2bb4f"}, - {file = "coverage-7.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633"}, - {file = "coverage-7.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b95c3a8cb0463ba9f77383d0fa8c9194cf91f64445a63fc26fb2327e1e1eb088"}, - {file = "coverage-7.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d7564cc09dd91b5a6001754a5b3c6ecc4aba6323baf33a12bd751036c998be4"}, - {file = "coverage-7.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44da56a2589b684813f86d07597fdf8a9c6ce77f58976727329272f5a01f99f7"}, - {file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e16f3d6b491c48c5ae726308e6ab1e18ee830b4cdd6913f2d7f77354b33f91c8"}, - {file = "coverage-7.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbc5958cb471e5a5af41b0ddaea96a37e74ed289535e8deca404811f6cb0bc3d"}, - {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a04e990a2a41740b02d6182b498ee9796cf60eefe40cf859b016650147908029"}, - {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ddbd2f9713a79e8e7242d7c51f1929611e991d855f414ca9996c20e44a895f7c"}, - {file = "coverage-7.5.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b1ccf5e728ccf83acd313c89f07c22d70d6c375a9c6f339233dcf792094bcbf7"}, - {file = "coverage-7.5.4-cp39-cp39-win32.whl", hash = "sha256:56b4eafa21c6c175b3ede004ca12c653a88b6f922494b023aeb1e836df953ace"}, - {file = "coverage-7.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:65e528e2e921ba8fd67d9055e6b9f9e34b21ebd6768ae1c1723f4ea6ace1234d"}, - {file = "coverage-7.5.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5"}, - {file = "coverage-7.5.4.tar.gz", hash = "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353"}, + {file = "coverage-7.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd"}, + {file = "coverage-7.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791"}, + {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6"}, + {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb"}, + {file = "coverage-7.6.0-cp310-cp310-win32.whl", hash = "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c"}, + {file = "coverage-7.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169"}, + {file = "coverage-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933"}, + {file = "coverage-7.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1"}, + {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d"}, + {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63"}, + {file = "coverage-7.6.0-cp311-cp311-win32.whl", hash = "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713"}, + {file = "coverage-7.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1"}, + {file = "coverage-7.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b"}, + {file = "coverage-7.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807"}, + {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee"}, + {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605"}, + {file = "coverage-7.6.0-cp312-cp312-win32.whl", hash = "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da"}, + {file = "coverage-7.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67"}, + {file = "coverage-7.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b"}, + {file = "coverage-7.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b"}, + {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6"}, + {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b"}, + {file = "coverage-7.6.0-cp38-cp38-win32.whl", hash = "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428"}, + {file = "coverage-7.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8"}, + {file = "coverage-7.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c"}, + {file = "coverage-7.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b"}, + {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166"}, + {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd"}, + {file = "coverage-7.6.0-cp39-cp39-win32.whl", hash = "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2"}, + {file = "coverage-7.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca"}, + {file = "coverage-7.6.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6"}, + {file = "coverage-7.6.0.tar.gz", hash = "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51"}, ] [package.extras] @@ -695,44 +758,38 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "42.0.8" +version = "43.0.0" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, - {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, - {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, - {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, - {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, - {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, - {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, - {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, + {file = "cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf"}, + {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55"}, + {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431"}, + {file = "cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc"}, + {file = "cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778"}, + {file = "cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f"}, + {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0"}, + {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b"}, + {file = "cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf"}, + {file = "cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c6d112bf61c5ef44042c253e4859b3cbbb50df2f78fa8fae6747a7814484a70"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:844b6d608374e7d08f4f6e6f9f7b951f9256db41421917dfb2d003dde4cd6b66"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51956cf8730665e2bdf8ddb8da0056f699c1a5715648c1b0144670c1ba00b48f"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:aae4d918f6b180a8ab8bf6511a419473d107df4dbb4225c7b48c5c9602c38c7f"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:232ce02943a579095a339ac4b390fbbe97f5b5d5d107f8a08260ea2768be8cc2"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5bcb8a5620008a8034d39bce21dc3e23735dfdb6a33a06974739bfa04f853947"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:08a24a7070b2b6804c1940ff0f910ff728932a9d0e80e7814234269f9d46d069"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e9c5266c432a1e23738d178e51c2c7a5e2ddf790f248be939448c0ba2021f9d1"}, + {file = "cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e"}, ] [package.dependencies] @@ -745,14 +802,13 @@ nox = ["nox"] pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.0)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] name = "cytoolz" version = "0.12.3" description = "Cython implementation of Toolz: High performance functional utilities" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -872,7 +928,6 @@ cython = ["cython"] name = "distlib" version = "0.3.8" description = "Distribution utilities" -category = "dev" optional = false python-versions = "*" files = [ @@ -884,7 +939,6 @@ files = [ name = "distro" version = "1.9.0" description = "Distro - an OS platform information API" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -896,7 +950,6 @@ files = [ name = "docker" version = "6.1.2" description = "A Python library for the Docker Engine API." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -919,7 +972,6 @@ ssh = ["paramiko (>=2.4.3)"] name = "dockerpty" version = "0.4.1" description = "Python library to use the pseudo-tty of a docker container" -category = "main" optional = false python-versions = "*" files = [ @@ -933,7 +985,6 @@ six = ">=1.3.0" name = "docopt" version = "0.6.2" description = "Pythonic argument parser, that will make you smile" -category = "main" optional = false python-versions = "*" files = [ @@ -944,7 +995,6 @@ files = [ name = "ecdsa" version = "0.16.1" description = "ECDSA cryptographic signature library (pure python)" -category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -963,7 +1013,6 @@ gmpy2 = ["gmpy2"] name = "eth-abi" version = "5.1.0" description = "eth_abi: Python utilities for working with Ethereum ABI definitions, especially encoding and decoding" -category = "main" optional = false python-versions = "<4,>=3.8" files = [ @@ -986,7 +1035,6 @@ tools = ["hypothesis (>=4.18.2,<5.0.0)"] name = "eth-account" version = "0.8.0" description = "eth-account: Sign Ethereum transactions and messages with local private keys" -category = "main" optional = false python-versions = ">=3.6, <4" files = [ @@ -1014,7 +1062,6 @@ test = ["coverage", "hypothesis (>=4.18.0,<5)", "pytest (>=6.2.5,<7)", "pytest-x name = "eth-hash" version = "0.7.0" description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" -category = "main" optional = false python-versions = ">=3.8, <4" files = [ @@ -1036,7 +1083,6 @@ test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] name = "eth-keyfile" version = "0.6.1" description = "A library for handling the encrypted keyfiles used to store ethereum private keys." -category = "main" optional = false python-versions = "*" files = [ @@ -1059,7 +1105,6 @@ test = ["pytest (>=6.2.5,<7)"] name = "eth-keys" version = "0.4.0" description = "Common API for Ethereum key operations." -category = "main" optional = false python-versions = "*" files = [ @@ -1082,7 +1127,6 @@ test = ["asn1tools (>=0.146.2,<0.147)", "eth-hash[pycryptodome]", "eth-hash[pysh name = "eth-rlp" version = "0.3.0" description = "eth-rlp: RLP definitions for common Ethereum objects in Python" -category = "main" optional = false python-versions = ">=3.7, <4" files = [ @@ -1105,7 +1149,6 @@ test = ["eth-hash[pycryptodome]", "pytest (>=6.2.5,<7)", "pytest-xdist", "tox (= name = "eth-typing" version = "3.5.2" description = "eth-typing: Common type annotations for ethereum python packages" -category = "main" optional = false python-versions = ">=3.7.2, <4" files = [ @@ -1126,7 +1169,6 @@ test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] name = "eth-utils" version = "2.3.1" description = "eth-utils: Common utility functions for python code that interacts with Ethereum" -category = "main" optional = false python-versions = ">=3.7,<4" files = [ @@ -1148,14 +1190,13 @@ test = ["hypothesis (>=4.43.0)", "mypy (==0.971)", "pytest (>=7.0.0)", "pytest-x [[package]] name = "exceptiongroup" -version = "1.2.1" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -1165,7 +1206,6 @@ test = ["pytest (>=6)"] name = "fastapi" version = "0.110.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1185,7 +1225,6 @@ all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" name = "filelock" version = "3.15.4" description = "A platform independent file lock." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1202,7 +1241,6 @@ typing = ["typing-extensions (>=4.8)"] name = "flask" version = "2.1.3" description = "A simple framework for building complex web applications." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1225,7 +1263,6 @@ dotenv = ["python-dotenv"] name = "frozenlist" version = "1.4.1" description = "A list-like structure which implements collections.abc.MutableSequence" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1312,7 +1349,6 @@ files = [ name = "googleapis-common-protos" version = "1.63.2" description = "Common protobufs used in Google APIs" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1330,7 +1366,6 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] name = "gql" version = "3.5.0" description = "GraphQL client for Python" -category = "main" optional = false python-versions = "*" files = [ @@ -1359,7 +1394,6 @@ websockets = ["websockets (>=10,<12)"] name = "graphql-core" version = "3.2.3" description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." -category = "main" optional = false python-versions = ">=3.6,<4" files = [ @@ -1369,68 +1403,66 @@ files = [ [[package]] name = "grpcio" -version = "1.64.1" +version = "1.65.1" description = "HTTP/2-based RPC framework" -category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "grpcio-1.64.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:55697ecec192bc3f2f3cc13a295ab670f51de29884ca9ae6cd6247df55df2502"}, - {file = "grpcio-1.64.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3b64ae304c175671efdaa7ec9ae2cc36996b681eb63ca39c464958396697daff"}, - {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:bac71b4b28bc9af61efcdc7630b166440bbfbaa80940c9a697271b5e1dabbc61"}, - {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c024ffc22d6dc59000faf8ad781696d81e8e38f4078cb0f2630b4a3cf231a90"}, - {file = "grpcio-1.64.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7cd5c1325f6808b8ae31657d281aadb2a51ac11ab081ae335f4f7fc44c1721d"}, - {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0a2813093ddb27418a4c99f9b1c223fab0b053157176a64cc9db0f4557b69bd9"}, - {file = "grpcio-1.64.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2981c7365a9353f9b5c864595c510c983251b1ab403e05b1ccc70a3d9541a73b"}, - {file = "grpcio-1.64.1-cp310-cp310-win32.whl", hash = "sha256:1262402af5a511c245c3ae918167eca57342c72320dffae5d9b51840c4b2f86d"}, - {file = "grpcio-1.64.1-cp310-cp310-win_amd64.whl", hash = "sha256:19264fc964576ddb065368cae953f8d0514ecc6cb3da8903766d9fb9d4554c33"}, - {file = "grpcio-1.64.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:58b1041e7c870bb30ee41d3090cbd6f0851f30ae4eb68228955d973d3efa2e61"}, - {file = "grpcio-1.64.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bbc5b1d78a7822b0a84c6f8917faa986c1a744e65d762ef6d8be9d75677af2ca"}, - {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:5841dd1f284bd1b3d8a6eca3a7f062b06f1eec09b184397e1d1d43447e89a7ae"}, - {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8caee47e970b92b3dd948371230fcceb80d3f2277b3bf7fbd7c0564e7d39068e"}, - {file = "grpcio-1.64.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73819689c169417a4f978e562d24f2def2be75739c4bed1992435d007819da1b"}, - {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6503b64c8b2dfad299749cad1b595c650c91e5b2c8a1b775380fcf8d2cbba1e9"}, - {file = "grpcio-1.64.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1de403fc1305fd96cfa75e83be3dee8538f2413a6b1685b8452301c7ba33c294"}, - {file = "grpcio-1.64.1-cp311-cp311-win32.whl", hash = "sha256:d4d29cc612e1332237877dfa7fe687157973aab1d63bd0f84cf06692f04c0367"}, - {file = "grpcio-1.64.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e56462b05a6f860b72f0fa50dca06d5b26543a4e88d0396259a07dc30f4e5aa"}, - {file = "grpcio-1.64.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:4657d24c8063e6095f850b68f2d1ba3b39f2b287a38242dcabc166453e950c59"}, - {file = "grpcio-1.64.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:62b4e6eb7bf901719fce0ca83e3ed474ae5022bb3827b0a501e056458c51c0a1"}, - {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:ee73a2f5ca4ba44fa33b4d7d2c71e2c8a9e9f78d53f6507ad68e7d2ad5f64a22"}, - {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:198908f9b22e2672a998870355e226a725aeab327ac4e6ff3a1399792ece4762"}, - {file = "grpcio-1.64.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b9d0acaa8d835a6566c640f48b50054f422d03e77e49716d4c4e8e279665a1"}, - {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5e42634a989c3aa6049f132266faf6b949ec2a6f7d302dbb5c15395b77d757eb"}, - {file = "grpcio-1.64.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b1a82e0b9b3022799c336e1fc0f6210adc019ae84efb7321d668129d28ee1efb"}, - {file = "grpcio-1.64.1-cp312-cp312-win32.whl", hash = "sha256:55260032b95c49bee69a423c2f5365baa9369d2f7d233e933564d8a47b893027"}, - {file = "grpcio-1.64.1-cp312-cp312-win_amd64.whl", hash = "sha256:c1a786ac592b47573a5bb7e35665c08064a5d77ab88a076eec11f8ae86b3e3f6"}, - {file = "grpcio-1.64.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:a011ac6c03cfe162ff2b727bcb530567826cec85eb8d4ad2bfb4bd023287a52d"}, - {file = "grpcio-1.64.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4d6dab6124225496010bd22690f2d9bd35c7cbb267b3f14e7a3eb05c911325d4"}, - {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a5e771d0252e871ce194d0fdcafd13971f1aae0ddacc5f25615030d5df55c3a2"}, - {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3c1b90ab93fed424e454e93c0ed0b9d552bdf1b0929712b094f5ecfe7a23ad"}, - {file = "grpcio-1.64.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20405cb8b13fd779135df23fabadc53b86522d0f1cba8cca0e87968587f50650"}, - {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0cc79c982ccb2feec8aad0e8fb0d168bcbca85bc77b080d0d3c5f2f15c24ea8f"}, - {file = "grpcio-1.64.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a3a035c37ce7565b8f4f35ff683a4db34d24e53dc487e47438e434eb3f701b2a"}, - {file = "grpcio-1.64.1-cp38-cp38-win32.whl", hash = "sha256:1257b76748612aca0f89beec7fa0615727fd6f2a1ad580a9638816a4b2eb18fd"}, - {file = "grpcio-1.64.1-cp38-cp38-win_amd64.whl", hash = "sha256:0a12ddb1678ebc6a84ec6b0487feac020ee2b1659cbe69b80f06dbffdb249122"}, - {file = "grpcio-1.64.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:75dbbf415026d2862192fe1b28d71f209e2fd87079d98470db90bebe57b33179"}, - {file = "grpcio-1.64.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e3d9f8d1221baa0ced7ec7322a981e28deb23749c76eeeb3d33e18b72935ab62"}, - {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5f8b75f64d5d324c565b263c67dbe4f0af595635bbdd93bb1a88189fc62ed2e5"}, - {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c84ad903d0d94311a2b7eea608da163dace97c5fe9412ea311e72c3684925602"}, - {file = "grpcio-1.64.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:940e3ec884520155f68a3b712d045e077d61c520a195d1a5932c531f11883489"}, - {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f10193c69fc9d3d726e83bbf0f3d316f1847c3071c8c93d8090cf5f326b14309"}, - {file = "grpcio-1.64.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac15b6c2c80a4d1338b04d42a02d376a53395ddf0ec9ab157cbaf44191f3ffdd"}, - {file = "grpcio-1.64.1-cp39-cp39-win32.whl", hash = "sha256:03b43d0ccf99c557ec671c7dede64f023c7da9bb632ac65dbc57f166e4970040"}, - {file = "grpcio-1.64.1-cp39-cp39-win_amd64.whl", hash = "sha256:ed6091fa0adcc7e4ff944090cf203a52da35c37a130efa564ded02b7aff63bcd"}, - {file = "grpcio-1.64.1.tar.gz", hash = "sha256:8d51dd1c59d5fa0f34266b80a3805ec29a1f26425c2a54736133f6d87fc4968a"}, + {file = "grpcio-1.65.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:3dc5f928815b8972fb83b78d8db5039559f39e004ec93ebac316403fe031a062"}, + {file = "grpcio-1.65.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:8333ca46053c35484c9f2f7e8d8ec98c1383a8675a449163cea31a2076d93de8"}, + {file = "grpcio-1.65.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:7af64838b6e615fff0ec711960ed9b6ee83086edfa8c32670eafb736f169d719"}, + {file = "grpcio-1.65.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbb64b4166362d9326f7efbf75b1c72106c1aa87f13a8c8b56a1224fac152f5c"}, + {file = "grpcio-1.65.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8422dc13ad93ec8caa2612b5032a2b9cd6421c13ed87f54db4a3a2c93afaf77"}, + {file = "grpcio-1.65.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4effc0562b6c65d4add6a873ca132e46ba5e5a46f07c93502c37a9ae7f043857"}, + {file = "grpcio-1.65.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a6c71575a2fedf259724981fd73a18906513d2f306169c46262a5bae956e6364"}, + {file = "grpcio-1.65.1-cp310-cp310-win32.whl", hash = "sha256:34966cf526ef0ea616e008d40d989463e3db157abb213b2f20c6ce0ae7928875"}, + {file = "grpcio-1.65.1-cp310-cp310-win_amd64.whl", hash = "sha256:ca931de5dd6d9eb94ff19a2c9434b23923bce6f767179fef04dfa991f282eaad"}, + {file = "grpcio-1.65.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:bbb46330cc643ecf10bd9bd4ca8e7419a14b6b9dedd05f671c90fb2c813c6037"}, + {file = "grpcio-1.65.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d827a6fb9215b961eb73459ad7977edb9e748b23e3407d21c845d1d8ef6597e5"}, + {file = "grpcio-1.65.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:6e71aed8835f8d9fbcb84babc93a9da95955d1685021cceb7089f4f1e717d719"}, + {file = "grpcio-1.65.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a1c84560b3b2d34695c9ba53ab0264e2802721c530678a8f0a227951f453462"}, + {file = "grpcio-1.65.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27adee2338d697e71143ed147fe286c05810965d5d30ec14dd09c22479bfe48a"}, + {file = "grpcio-1.65.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f62652ddcadc75d0e7aa629e96bb61658f85a993e748333715b4ab667192e4e8"}, + {file = "grpcio-1.65.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:71a05fd814700dd9cb7d9a507f2f6a1ef85866733ccaf557eedacec32d65e4c2"}, + {file = "grpcio-1.65.1-cp311-cp311-win32.whl", hash = "sha256:b590f1ad056294dfaeac0b7e1b71d3d5ace638d8dd1f1147ce4bd13458783ba8"}, + {file = "grpcio-1.65.1-cp311-cp311-win_amd64.whl", hash = "sha256:12e9bdf3b5fd48e5fbe5b3da382ad8f97c08b47969f3cca81dd9b36b86ed39e2"}, + {file = "grpcio-1.65.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:54cb822e177374b318b233e54b6856c692c24cdbd5a3ba5335f18a47396bac8f"}, + {file = "grpcio-1.65.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:aaf3c54419a28d45bd1681372029f40e5bfb58e5265e3882eaf21e4a5f81a119"}, + {file = "grpcio-1.65.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:557de35bdfbe8bafea0a003dbd0f4da6d89223ac6c4c7549d78e20f92ead95d9"}, + {file = "grpcio-1.65.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8bfd95ef3b097f0cc86ade54eafefa1c8ed623aa01a26fbbdcd1a3650494dd11"}, + {file = "grpcio-1.65.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e6a8f3d6c41e6b642870afe6cafbaf7b61c57317f9ec66d0efdaf19db992b90"}, + {file = "grpcio-1.65.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1faaf7355ceed07ceaef0b9dcefa4c98daf1dd8840ed75c2de128c3f4a4d859d"}, + {file = "grpcio-1.65.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:60f1f38eed830488ad2a1b11579ef0f345ff16fffdad1d24d9fbc97ba31804ff"}, + {file = "grpcio-1.65.1-cp312-cp312-win32.whl", hash = "sha256:e75acfa52daf5ea0712e8aa82f0003bba964de7ae22c26d208cbd7bc08500177"}, + {file = "grpcio-1.65.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff5a84907e51924973aa05ed8759210d8cdae7ffcf9e44fd17646cf4a902df59"}, + {file = "grpcio-1.65.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:1fbd6331f18c3acd7e09d17fd840c096f56eaf0ef830fbd50af45ae9dc8dfd83"}, + {file = "grpcio-1.65.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:de5b6be29116e094c5ef9d9e4252e7eb143e3d5f6bd6d50a78075553ab4930b0"}, + {file = "grpcio-1.65.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:e4a3cdba62b2d6aeae6027ae65f350de6dc082b72e6215eccf82628e79efe9ba"}, + {file = "grpcio-1.65.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:941c4869aa229d88706b78187d60d66aca77fe5c32518b79e3c3e03fc26109a2"}, + {file = "grpcio-1.65.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f40cebe5edb518d78b8131e87cb83b3ee688984de38a232024b9b44e74ee53d3"}, + {file = "grpcio-1.65.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2ca684ba331fb249d8a1ce88db5394e70dbcd96e58d8c4b7e0d7b141a453dce9"}, + {file = "grpcio-1.65.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8558f0083ddaf5de64a59c790bffd7568e353914c0c551eae2955f54ee4b857f"}, + {file = "grpcio-1.65.1-cp38-cp38-win32.whl", hash = "sha256:8d8143a3e3966f85dce6c5cc45387ec36552174ba5712c5dc6fcc0898fb324c0"}, + {file = "grpcio-1.65.1-cp38-cp38-win_amd64.whl", hash = "sha256:76e81a86424d6ca1ce7c16b15bdd6a964a42b40544bf796a48da241fdaf61153"}, + {file = "grpcio-1.65.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:cb5175f45c980ff418998723ea1b3869cce3766d2ab4e4916fbd3cedbc9d0ed3"}, + {file = "grpcio-1.65.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b12c1aa7b95abe73b3e04e052c8b362655b41c7798da69f1eaf8d186c7d204df"}, + {file = "grpcio-1.65.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:3019fb50128b21a5e018d89569ffaaaa361680e1346c2f261bb84a91082eb3d3"}, + {file = "grpcio-1.65.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ae15275ed98ea267f64ee9ddedf8ecd5306a5b5bb87972a48bfe24af24153e8"}, + {file = "grpcio-1.65.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f096ffb881f37e8d4f958b63c74bfc400c7cebd7a944b027357cd2fb8d91a57"}, + {file = "grpcio-1.65.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2f56b5a68fdcf17a0a1d524bf177218c3c69b3947cb239ea222c6f1867c3ab68"}, + {file = "grpcio-1.65.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:941596d419b9736ab548aa0feb5bbba922f98872668847bf0720b42d1d227b9e"}, + {file = "grpcio-1.65.1-cp39-cp39-win32.whl", hash = "sha256:5fd7337a823b890215f07d429f4f193d24b80d62a5485cf88ee06648591a0c57"}, + {file = "grpcio-1.65.1-cp39-cp39-win_amd64.whl", hash = "sha256:1bceeec568372cbebf554eae1b436b06c2ff24cfaf04afade729fb9035408c6c"}, + {file = "grpcio-1.65.1.tar.gz", hash = "sha256:3c492301988cd720cd145d84e17318d45af342e29ef93141228f9cd73222368b"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.64.1)"] +protobuf = ["grpcio-tools (>=1.65.1)"] [[package]] name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1442,7 +1474,6 @@ files = [ name = "hexbytes" version = "0.3.1" description = "hexbytes: Python `bytes` subclass that decodes hex, with a readable console output" -category = "main" optional = false python-versions = ">=3.7, <4" files = [ @@ -1460,7 +1491,6 @@ test = ["eth-utils (>=1.0.1,<3)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>= name = "idna" version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1470,14 +1500,13 @@ files = [ [[package]] name = "importlib-metadata" -version = "8.0.0" +version = "8.2.0" description = "Read metadata from Python packages" -category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"}, - {file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"}, + {file = "importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369"}, + {file = "importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"}, ] [package.dependencies] @@ -1492,7 +1521,6 @@ test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "p name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1504,7 +1532,6 @@ files = [ name = "ipfshttpclient" version = "0.8.0a2" description = "Python IPFS HTTP CLIENT library" -category = "main" optional = false python-versions = ">=3.6.2,!=3.7.0,!=3.7.1" files = [ @@ -1520,7 +1547,6 @@ requests = ">=2.11" name = "itsdangerous" version = "2.2.0" description = "Safely pass data to untrusted environments and back." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1532,7 +1558,6 @@ files = [ name = "jinja2" version = "3.1.4" description = "A very fast and expressive template engine." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1550,7 +1575,6 @@ i18n = ["Babel (>=2.7)"] name = "jsonschema" version = "4.3.3" description = "An implementation of JSON Schema validation for Python" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1570,7 +1594,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- name = "lru-dict" version = "1.3.0" description = "An Dict like LRU container." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1664,7 +1687,6 @@ test = ["pytest"] name = "macholib" version = "1.16.3" description = "Mach-O header analysis and editing" -category = "main" optional = false python-versions = "*" files = [ @@ -1679,7 +1701,6 @@ altgraph = ">=0.17" name = "markupsafe" version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1749,7 +1770,6 @@ files = [ name = "morphys" version = "1.0" description = "Smart conversions between unicode and bytes types for common cases" -category = "main" optional = false python-versions = "*" files = [ @@ -1760,7 +1780,6 @@ files = [ name = "multiaddr" version = "0.0.9" description = "Python implementation of jbenet's multiaddr" -category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" files = [ @@ -1778,7 +1797,6 @@ varint = "*" name = "multidict" version = "6.0.5" description = "multidict implementation" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1878,7 +1896,6 @@ files = [ name = "netaddr" version = "1.3.0" description = "A network address manipulation library for Python" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1891,24 +1908,23 @@ nicer-shell = ["ipython"] [[package]] name = "open-aea" -version = "1.51.0" +version = "1.53.0" description = "Open Autonomous Economic Agent framework (without vendor lock-in)" -category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "open-aea-1.51.0.tar.gz", hash = "sha256:a1b6b6be9c08cfc8eb0befd436f0b821d4b0cd9cabec4154e36695fd8bc555ec"}, - {file = "open_aea-1.51.0-py3-none-any.whl", hash = "sha256:94a93fef676352fba8a7fa2a0a68b140e9ca9f8999f78bf24c66bb4557b8e6f7"}, - {file = "open_aea-1.51.0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:8887b1604163f5be1706fce5b9cbc5592b22d9ae621c200f77550ee76d487dc8"}, - {file = "open_aea-1.51.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:c16001b336b61863eb8bb557161718e0110853064a6f1afb990fd02fa672e307"}, - {file = "open_aea-1.51.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0c4abbf61de198f708a20b3cedd617b922727090781720687eb663288b015953"}, - {file = "open_aea-1.51.0-py3-none-win32.whl", hash = "sha256:75158aeaa4e395c92116581a0534d652979e3a0ce4986665207cde8050521467"}, - {file = "open_aea-1.51.0-py3-none-win_amd64.whl", hash = "sha256:b2eee2d1ee065d1cc48d73aa7db82256c80b792cf14ab4765c4a087af3087464"}, + {file = "open_aea-1.53.0-py3-none-any.whl", hash = "sha256:1244855875effe09e2c965750ac401a973a1ae56cdc880045eea70f19ed90dcb"}, + {file = "open_aea-1.53.0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:d0a848e33798599953dc764d37083fc37642140a91624e06a56b8d2f95ae6cb9"}, + {file = "open_aea-1.53.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:48f5715f13a0389799b9461bc776e9638e6ae38173d0f2bf6d28bad637232914"}, + {file = "open_aea-1.53.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:87e4ae903ec9a7268eba0ead449f9693cb5bedb6dfc5846c90f94f2354bd35ab"}, + {file = "open_aea-1.53.0-py3-none-win32.whl", hash = "sha256:182e9f8a77fe8efcc768360ac7308a0951ec16bcb12e2ad4f55886b12258d702"}, + {file = "open_aea-1.53.0-py3-none-win_amd64.whl", hash = "sha256:cef9d4d177ea7d959ebacab962fbd1d03d7243c0b72d10a3ee7850df8d922e06"}, + {file = "open_aea-1.53.0.tar.gz", hash = "sha256:6fcb82ceed0b6841c0f41d116b207308556e3d18807fe140e9ef1a898c7a8a0b"}, ] [package.dependencies] base58 = ">=1.0.3,<3.0.0" -click = {version = "8.0.2", optional = true, markers = "extra == \"all\""} +click = {version = ">=8.1.0,<9", optional = true, markers = "extra == \"all\""} coverage = {version = ">=6.4.4,<8.0.0", optional = true, markers = "extra == \"all\""} ecdsa = ">=0.15,<0.17.0" jsonschema = ">=4.3.0,<4.4.0" @@ -1919,26 +1935,25 @@ py-multibase = ">=1.0.0" py-multicodec = ">=0.2.0" pymultihash = "0.8.2" pytest = {version = ">=7.0.0,<7.3.0", optional = true, markers = "extra == \"all\""} -python-dotenv = ">=0.14.0,<0.22.0" -pyyaml = "6.0.1" -requests = "2.28.1" +python-dotenv = ">=0.14.0,<1.0.1" +pyyaml = {version = ">=6.0.1,<7", optional = true, markers = "extra == \"all\""} +requests = ">=2.28.1,<3" semver = ">=2.9.1,<3.0.0" [package.extras] -all = ["click (==8.0.2)", "coverage (>=6.4.4,<8.0.0)", "jsonschema (>=4.3.0,<4.4.0)", "packaging (>=23.1,<24.0)", "pytest (>=7.0.0,<7.3.0)", "pyyaml (==6.0.1)", "semver (>=2.9.1,<3.0.0)"] -cli = ["click (==8.0.2)", "coverage (>=6.4.4,<8.0.0)", "jsonschema (>=4.3.0,<4.4.0)", "packaging (>=23.1,<24.0)", "pytest (>=7.0.0,<7.3.0)", "pyyaml (==6.0.1)", "semver (>=2.9.1,<3.0.0)"] -test-tools = ["click (==8.0.2)", "coverage (>=6.4.4,<8.0.0)", "jsonschema (>=4.3.0,<4.4.0)", "packaging (>=23.1,<24.0)", "pytest (>=7.0.0,<7.3.0)", "pyyaml (==6.0.1)", "semver (>=2.9.1,<3.0.0)"] +all = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "jsonschema (>=4.3.0,<4.4.0)", "packaging (>=23.1,<24.0)", "pytest (>=7.0.0,<7.3.0)", "pyyaml (>=6.0.1,<9)", "semver (>=2.9.1,<3.0.0)"] +cli = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "jsonschema (>=4.3.0,<4.4.0)", "packaging (>=23.1,<24.0)", "pytest (>=7.0.0,<7.3.0)", "pyyaml (>=6.0.1,<9)", "semver (>=2.9.1,<3.0.0)"] +test-tools = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "jsonschema (>=4.3.0,<4.4.0)", "packaging (>=23.1,<24.0)", "pytest (>=7.0.0,<7.3.0)", "pyyaml (>=6.0.1,<9)", "semver (>=2.9.1,<3.0.0)"] [[package]] name = "open-aea-cli-ipfs" -version = "1.51.0" +version = "1.53.0" description = "CLI extension for open AEA framework wrapping IPFS functionality." -category = "main" optional = false python-versions = "*" files = [ - {file = "open-aea-cli-ipfs-1.51.0.tar.gz", hash = "sha256:142174bb7516b8562a0114838c95d1466d4d4857a8d0aaaf076dd571b346f6c5"}, - {file = "open_aea_cli_ipfs-1.51.0-py3-none-any.whl", hash = "sha256:8c8e422bb63108fef65f5360374598275c737cb15df571f13af11f07961380e3"}, + {file = "open_aea_cli_ipfs-1.53.0-py3-none-any.whl", hash = "sha256:335a02473d1c6820bb63a31e2931749ba644f586a7acbc650da9efc4c7168efa"}, + {file = "open_aea_cli_ipfs-1.53.0.tar.gz", hash = "sha256:499a66a45925064e6946ec72f482182390263cc7726409832f1317fe831b6289"}, ] [package.dependencies] @@ -1950,7 +1965,6 @@ pytest = ">=7.0.0,<7.3.0" name = "open-aea-flashbots" version = "1.4.0" description = "" -category = "main" optional = false python-versions = ">=3.9,<4.0" files = [ @@ -1964,18 +1978,17 @@ web3 = ">=6.0.0,<7" [[package]] name = "open-aea-ledger-cosmos" -version = "1.51.0" +version = "1.53.0" description = "Python package wrapping the public and private key cryptography and ledger api of Cosmos." -category = "main" optional = false python-versions = "*" files = [ - {file = "open-aea-ledger-cosmos-1.51.0.tar.gz", hash = "sha256:d2b15cd4b5e6ba3bda2d7206689000356c0197508eea8031dced67a0965c2648"}, - {file = "open_aea_ledger_cosmos-1.51.0-py3-none-any.whl", hash = "sha256:a9f46895a502397d2b95c2cec13f0f12777e7f4811f27b5314e5363d44471ca5"}, + {file = "open_aea_ledger_cosmos-1.53.0-py3-none-any.whl", hash = "sha256:79b2eafc8723593634b72973da39e3e3c01bceae04b330b51a5059eb1200262b"}, + {file = "open_aea_ledger_cosmos-1.53.0.tar.gz", hash = "sha256:14a032918d7f0659fedbe21a53fa668b24505bb9e97358340b20325943f9fa26"}, ] [package.dependencies] -bech32 = "1.2.0" +bech32 = ">=1.2.0,<2" cosmpy = "0.9.2" ecdsa = ">=0.15,<0.17.0" open-aea = ">=1.0.0,<2.0.0" @@ -1983,14 +1996,13 @@ pycryptodome = ">=3.10.1,<4.0.0" [[package]] name = "open-aea-ledger-ethereum" -version = "1.51.0" +version = "1.53.0" description = "Python package wrapping the public and private key cryptography and ledger api of Ethereum." -category = "main" optional = false python-versions = "*" files = [ - {file = "open-aea-ledger-ethereum-1.51.0.tar.gz", hash = "sha256:3e47bcac5f0e062d8cf1837b120d259942a6194effe54c0febc876d528b8269b"}, - {file = "open_aea_ledger_ethereum-1.51.0-py3-none-any.whl", hash = "sha256:6c6d17c4170125af1bfcf0de80700c89d4cbec75fc4a39c43080476637847d33"}, + {file = "open_aea_ledger_ethereum-1.53.0-py3-none-any.whl", hash = "sha256:501eb9e9e228552bf9f6f8811d780f33dbbf477ddb33b63d335caaeb24840274"}, + {file = "open_aea_ledger_ethereum-1.53.0.tar.gz", hash = "sha256:734f335061c33a171b945ab1bcea5d47be9b9532457ed361b3aab727e85bca0d"}, ] [package.dependencies] @@ -2001,46 +2013,45 @@ web3 = ">=6.0.0,<7" [[package]] name = "open-aea-ledger-ethereum-flashbots" -version = "1.51.0" +version = "1.53.0" description = "Python package extending the default open-aea ethereum ledger plugin to add support for flashbots." -category = "main" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "open-aea-ledger-ethereum-flashbots-1.51.0.tar.gz", hash = "sha256:5e474c0d3cf7cbd8a8b55e3168877cd844daaacba1a2e8cf4eed6dddbad45504"}, - {file = "open_aea_ledger_ethereum_flashbots-1.51.0-py3-none-any.whl", hash = "sha256:6c30fa54f1f77f59adea01632f61c7cd162f8e2ab74ecba0201e21c206626da9"}, + {file = "open_aea_ledger_ethereum_flashbots-1.53.0-py3-none-any.whl", hash = "sha256:04e1d04b68159f092dbe8c94d419221ad45bac17497c8feed9cbe92270a675b3"}, + {file = "open_aea_ledger_ethereum_flashbots-1.53.0.tar.gz", hash = "sha256:683e0c73c04413a0098f4903e3afa8c1570f8c51591ad6cef66fd38cfad463d8"}, ] [package.dependencies] open-aea-flashbots = "1.4.0" -open-aea-ledger-ethereum = ">=1.51.0,<1.52.0" +open-aea-ledger-ethereum = ">=1.53.0,<1.54.0" [[package]] name = "open-autonomy" -version = "0.14.11.post1" +version = "0.14.14.post2" description = "A framework for the creation of autonomous agent services." -category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "open-autonomy-0.14.11.post1.tar.gz", hash = "sha256:b44467cccffa3c72db21baca127d747fb62a60a22161613c4248e7cec78a0bb6"}, - {file = "open_autonomy-0.14.11.post1-py3-none-any.whl", hash = "sha256:1f2d8d22909c90f679fb6c24318abe8887f94668aa9decf018837853c828bc4a"}, + {file = "open_autonomy-0.14.14.post2-py3-none-any.whl", hash = "sha256:76efc0ce814c748eb02176477eef5b5ca4c6a84d77230e01a40c3df5ad2254b8"}, + {file = "open_autonomy-0.14.14.post2.tar.gz", hash = "sha256:0e1e7f3207fde38b8778a260c43153737a3b9fefe6d7abf373710a1aae9e267b"}, ] [package.dependencies] aiohttp = ">=3.8.5,<4.0.0" -click = "8.0.2" +click = ">=8.1.0,<9" coverage = ">=6.4.4,<8.0.0" docker = "6.1.2" Flask = ">=2.0.2,<3.0.0" gql = "3.5.0" hexbytes = "*" jsonschema = ">=4.3.0,<4.4.0" -open-aea = {version = "1.51.0", extras = ["all"]} -open-aea-cli-ipfs = "1.51.0" +open-aea = {version = "1.53.0", extras = ["all"]} +open-aea-cli-ipfs = "1.53.0" protobuf = ">=4.21.6,<4.25.0" pytest = "7.2.1" python-dotenv = ">=0.14.5,<0.22.0" +requests = ">=2.28.1,<2.31.2" requests-toolbelt = "1.0.0" texttable = "1.6.7" typing-extensions = ">=3.10.0.2" @@ -2049,14 +2060,13 @@ watchdog = ">=2.1.6" werkzeug = "2.0.3" [package.extras] -all = ["click (==8.0.2)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.51.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] -cli = ["click (==8.0.2)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.51.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] +all = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.53.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] +cli = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.53.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] [[package]] name = "packaging" version = "23.2" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2068,7 +2078,6 @@ files = [ name = "paramiko" version = "3.4.0" description = "SSH2 protocol library" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2090,7 +2099,6 @@ invoke = ["invoke (>=2.0)"] name = "parsimonious" version = "0.10.0" description = "(Soon to be) the fastest pure-Python PEG parser I could muster" -category = "main" optional = false python-versions = "*" files = [ @@ -2105,7 +2113,6 @@ regex = ">=2022.3.15" name = "pefile" version = "2023.2.7" description = "Python PE parsing module" -category = "main" optional = false python-versions = ">=3.6.0" files = [ @@ -2117,7 +2124,6 @@ files = [ name = "platformdirs" version = "4.2.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2134,7 +2140,6 @@ type = ["mypy (>=1.8)"] name = "pluggy" version = "1.5.0" description = "plugin and hook calling mechanisms for python" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2150,7 +2155,6 @@ testing = ["pytest", "pytest-benchmark"] name = "protobuf" version = "4.24.4" description = "" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2173,7 +2177,6 @@ files = [ name = "psutil" version = "5.9.8" description = "Cross-platform lib for process and system monitoring in Python." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -2202,7 +2205,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -2214,7 +2216,6 @@ files = [ name = "py-multibase" version = "1.0.3" description = "Multibase implementation for Python" -category = "main" optional = false python-versions = "*" files = [ @@ -2231,7 +2232,6 @@ six = ">=1.10.0,<2.0" name = "py-multicodec" version = "0.2.1" description = "Multicodec implementation in Python" -category = "main" optional = false python-versions = "*" files = [ @@ -2248,7 +2248,6 @@ varint = ">=1.0.2,<2.0.0" name = "pycparser" version = "2.22" description = "C parser in Python" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2260,7 +2259,6 @@ files = [ name = "pycryptodome" version = "3.20.0" description = "Cryptographic library for Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -2302,7 +2300,6 @@ files = [ name = "pydantic" version = "2.8.2" description = "Data validation using Python type hints" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2322,7 +2319,6 @@ email = ["email-validator (>=2.0.0)"] name = "pydantic-core" version = "2.20.1" description = "Core functionality for Pydantic validation and serialization" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2422,24 +2418,23 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pyinstaller" -version = "6.8.0" +version = "6.9.0" description = "PyInstaller bundles a Python application and all its dependencies into a single package." -category = "main" optional = false python-versions = "<3.13,>=3.8" files = [ - {file = "pyinstaller-6.8.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:5ff6bc2784c1026f8e2f04aa3760cbed41408e108a9d4cf1dd52ee8351a3f6e1"}, - {file = "pyinstaller-6.8.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:39ac424d2ee2457d2ab11a5091436e75a0cccae207d460d180aa1fcbbafdd528"}, - {file = "pyinstaller-6.8.0-py3-none-manylinux2014_i686.whl", hash = "sha256:355832a3acc7de90a255ecacd4b9f9e166a547a79c8905d49f14e3a75c1acdb9"}, - {file = "pyinstaller-6.8.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:6303c7a009f47e6a96ef65aed49f41e36ece8d079b9193ca92fe807403e5fe80"}, - {file = "pyinstaller-6.8.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2b71509468c811968c0b5decb5bbe85b6292ea52d7b1f26313d2aabb673fa9a5"}, - {file = "pyinstaller-6.8.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ff31c5b99e05a4384bbe2071df67ec8b2b347640a375eae9b40218be2f1754c6"}, - {file = "pyinstaller-6.8.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:000c36b13fe4cd8d0d8c2bc855b1ddcf39867b5adf389e6b5ca45b25fa3e619d"}, - {file = "pyinstaller-6.8.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:fe0af018d7d5077180e3144ada89a4da5df8d07716eb7e9482834a56dc57a4e8"}, - {file = "pyinstaller-6.8.0-py3-none-win32.whl", hash = "sha256:d257f6645c7334cbd66f38a4fac62c3ad614cc46302b2b5d9f8cc48c563bce0e"}, - {file = "pyinstaller-6.8.0-py3-none-win_amd64.whl", hash = "sha256:81cccfa9b16699b457f4788c5cc119b50f3cd4d0db924955f15c33f2ad27a50d"}, - {file = "pyinstaller-6.8.0-py3-none-win_arm64.whl", hash = "sha256:1c3060a263758cf7f0144ab4c016097b20451b2469d468763414665db1bb743d"}, - {file = "pyinstaller-6.8.0.tar.gz", hash = "sha256:3f4b6520f4423fe19bcc2fd63ab7238851ae2bdcbc98f25bc5d2f97cc62012e9"}, + {file = "pyinstaller-6.9.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:5ced2e83acf222b936ea94abc5a5cc96588705654b39138af8fb321d9cf2b954"}, + {file = "pyinstaller-6.9.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:f18a3d551834ef8fb7830d48d4cc1527004d0e6b51ded7181e78374ad6111846"}, + {file = "pyinstaller-6.9.0-py3-none-manylinux2014_i686.whl", hash = "sha256:f2fc568de3d6d2a176716a3fc9f20da06d351e8bea5ddd10ecb5659fce3a05b0"}, + {file = "pyinstaller-6.9.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:a0f378f64ad0655d11ade9fde7877e7573fd3d5066231608ce7dfa9040faecdd"}, + {file = "pyinstaller-6.9.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:7bf0c13c5a8560c89540746ae742f4f4b82290e95a6b478374d9f34959fe25d6"}, + {file = "pyinstaller-6.9.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:da994aba14c5686db88796684de265a8665733b4df09b939f7ebdf097d18df72"}, + {file = "pyinstaller-6.9.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:4e3e50743c091a06e6d01c59bdd6d03967b453ee5384a9e790759be4129db4a4"}, + {file = "pyinstaller-6.9.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:b041be2fe78da47a269604d62c940d68c62f9a3913bdf64af4123f7689d47099"}, + {file = "pyinstaller-6.9.0-py3-none-win32.whl", hash = "sha256:2bf4de17a1c63c0b797b38e13bfb4d03b5ee7c0a68e28b915a7eaacf6b76087f"}, + {file = "pyinstaller-6.9.0-py3-none-win_amd64.whl", hash = "sha256:43709c70b1da8441a730327a8ed362bfcfdc3d42c1bf89f3e2b0a163cc4e7d33"}, + {file = "pyinstaller-6.9.0-py3-none-win_arm64.whl", hash = "sha256:f15c1ef11ed5ceb32447dfbdab687017d6adbef7fc32aa359d584369bfe56eda"}, + {file = "pyinstaller-6.9.0.tar.gz", hash = "sha256:f4a75c552facc2e2a370f1e422b971b5e5cdb4058ff38cea0235aa21fc0b378f"}, ] [package.dependencies] @@ -2448,7 +2443,7 @@ importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""} macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""} packaging = ">=22.0" pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""} -pyinstaller-hooks-contrib = ">=2024.6" +pyinstaller-hooks-contrib = ">=2024.7" pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""} setuptools = ">=42.0.0" @@ -2460,7 +2455,6 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"] name = "pyinstaller-hooks-contrib" version = "2024.7" description = "Community maintained hooks for PyInstaller" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2477,7 +2471,6 @@ setuptools = ">=42.0.0" name = "pymultihash" version = "0.8.2" description = "Python implementation of the multihash specification" -category = "main" optional = false python-versions = "*" files = [ @@ -2493,7 +2486,6 @@ sha3 = ["pysha3"] name = "pynacl" version = "1.5.0" description = "Python binding to the Networking and Cryptography (NaCl) library" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2520,7 +2512,6 @@ tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] name = "pyrsistent" version = "0.20.0" description = "Persistent/Functional/Immutable data structures" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2562,7 +2553,6 @@ files = [ name = "pytest" version = "7.2.1" description = "pytest: simple powerful testing with Python" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2586,7 +2576,6 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2. name = "python-baseconv" version = "1.2.2" description = "Convert numbers from base 10 integers to base X strings and back again." -category = "main" optional = false python-versions = "*" files = [ @@ -2597,7 +2586,6 @@ files = [ name = "python-dateutil" version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -2612,7 +2600,6 @@ six = ">=1.5" name = "python-dotenv" version = "0.21.1" description = "Read key-value pairs from a .env file and set them as environment variables" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2627,7 +2614,6 @@ cli = ["click (>=5.0)"] name = "pywin32" version = "306" description = "Python for Window Extensions" -category = "main" optional = false python-versions = "*" files = [ @@ -2651,7 +2637,6 @@ files = [ name = "pywin32-ctypes" version = "0.2.2" description = "A (partial) reimplementation of pywin32 using ctypes/cffi" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2663,7 +2648,6 @@ files = [ name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2722,110 +2706,108 @@ files = [ [[package]] name = "regex" -version = "2024.5.15" +version = "2024.7.24" description = "Alternative regular expression module, to replace re." -category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a81e3cfbae20378d75185171587cbf756015ccb14840702944f014e0d93ea09f"}, - {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b59138b219ffa8979013be7bc85bb60c6f7b7575df3d56dc1e403a438c7a3f6"}, - {file = "regex-2024.5.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0bd000c6e266927cb7a1bc39d55be95c4b4f65c5be53e659537537e019232b1"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eaa7ddaf517aa095fa8da0b5015c44d03da83f5bd49c87961e3c997daed0de7"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba68168daedb2c0bab7fd7e00ced5ba90aebf91024dea3c88ad5063c2a562cca"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e8d717bca3a6e2064fc3a08df5cbe366369f4b052dcd21b7416e6d71620dca1"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1337b7dbef9b2f71121cdbf1e97e40de33ff114801263b275aafd75303bd62b5"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9ebd0a36102fcad2f03696e8af4ae682793a5d30b46c647eaf280d6cfb32796"}, - {file = "regex-2024.5.15-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9efa1a32ad3a3ea112224897cdaeb6aa00381627f567179c0314f7b65d354c62"}, - {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1595f2d10dff3d805e054ebdc41c124753631b6a471b976963c7b28543cf13b0"}, - {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b802512f3e1f480f41ab5f2cfc0e2f761f08a1f41092d6718868082fc0d27143"}, - {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a0981022dccabca811e8171f913de05720590c915b033b7e601f35ce4ea7019f"}, - {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:19068a6a79cf99a19ccefa44610491e9ca02c2be3305c7760d3831d38a467a6f"}, - {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1b5269484f6126eee5e687785e83c6b60aad7663dafe842b34691157e5083e53"}, - {file = "regex-2024.5.15-cp310-cp310-win32.whl", hash = "sha256:ada150c5adfa8fbcbf321c30c751dc67d2f12f15bd183ffe4ec7cde351d945b3"}, - {file = "regex-2024.5.15-cp310-cp310-win_amd64.whl", hash = "sha256:ac394ff680fc46b97487941f5e6ae49a9f30ea41c6c6804832063f14b2a5a145"}, - {file = "regex-2024.5.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f5b1dff3ad008dccf18e652283f5e5339d70bf8ba7c98bf848ac33db10f7bc7a"}, - {file = "regex-2024.5.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c6a2b494a76983df8e3d3feea9b9ffdd558b247e60b92f877f93a1ff43d26656"}, - {file = "regex-2024.5.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a32b96f15c8ab2e7d27655969a23895eb799de3665fa94349f3b2fbfd547236f"}, - {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10002e86e6068d9e1c91eae8295ef690f02f913c57db120b58fdd35a6bb1af35"}, - {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec54d5afa89c19c6dd8541a133be51ee1017a38b412b1321ccb8d6ddbeb4cf7d"}, - {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10e4ce0dca9ae7a66e6089bb29355d4432caed736acae36fef0fdd7879f0b0cb"}, - {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e507ff1e74373c4d3038195fdd2af30d297b4f0950eeda6f515ae3d84a1770f"}, - {file = "regex-2024.5.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1f059a4d795e646e1c37665b9d06062c62d0e8cc3c511fe01315973a6542e40"}, - {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0721931ad5fe0dda45d07f9820b90b2148ccdd8e45bb9e9b42a146cb4f695649"}, - {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:833616ddc75ad595dee848ad984d067f2f31be645d603e4d158bba656bbf516c"}, - {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:287eb7f54fc81546346207c533ad3c2c51a8d61075127d7f6d79aaf96cdee890"}, - {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:19dfb1c504781a136a80ecd1fff9f16dddf5bb43cec6871778c8a907a085bb3d"}, - {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:119af6e56dce35e8dfb5222573b50c89e5508d94d55713c75126b753f834de68"}, - {file = "regex-2024.5.15-cp311-cp311-win32.whl", hash = "sha256:1c1c174d6ec38d6c8a7504087358ce9213d4332f6293a94fbf5249992ba54efa"}, - {file = "regex-2024.5.15-cp311-cp311-win_amd64.whl", hash = "sha256:9e717956dcfd656f5055cc70996ee2cc82ac5149517fc8e1b60261b907740201"}, - {file = "regex-2024.5.15-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:632b01153e5248c134007209b5c6348a544ce96c46005d8456de1d552455b014"}, - {file = "regex-2024.5.15-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e64198f6b856d48192bf921421fdd8ad8eb35e179086e99e99f711957ffedd6e"}, - {file = "regex-2024.5.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68811ab14087b2f6e0fc0c2bae9ad689ea3584cad6917fc57be6a48bbd012c49"}, - {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ec0c2fea1e886a19c3bee0cd19d862b3aa75dcdfb42ebe8ed30708df64687a"}, - {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0c0c0003c10f54a591d220997dd27d953cd9ccc1a7294b40a4be5312be8797b"}, - {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2431b9e263af1953c55abbd3e2efca67ca80a3de8a0437cb58e2421f8184717a"}, - {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a605586358893b483976cffc1723fb0f83e526e8f14c6e6614e75919d9862cf"}, - {file = "regex-2024.5.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391d7f7f1e409d192dba8bcd42d3e4cf9e598f3979cdaed6ab11288da88cb9f2"}, - {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9ff11639a8d98969c863d4617595eb5425fd12f7c5ef6621a4b74b71ed8726d5"}, - {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4eee78a04e6c67e8391edd4dad3279828dd66ac4b79570ec998e2155d2e59fd5"}, - {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8fe45aa3f4aa57faabbc9cb46a93363edd6197cbc43523daea044e9ff2fea83e"}, - {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d0a3d8d6acf0c78a1fff0e210d224b821081330b8524e3e2bc5a68ef6ab5803d"}, - {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c486b4106066d502495b3025a0a7251bf37ea9540433940a23419461ab9f2a80"}, - {file = "regex-2024.5.15-cp312-cp312-win32.whl", hash = "sha256:c49e15eac7c149f3670b3e27f1f28a2c1ddeccd3a2812cba953e01be2ab9b5fe"}, - {file = "regex-2024.5.15-cp312-cp312-win_amd64.whl", hash = "sha256:673b5a6da4557b975c6c90198588181029c60793835ce02f497ea817ff647cb2"}, - {file = "regex-2024.5.15-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:87e2a9c29e672fc65523fb47a90d429b70ef72b901b4e4b1bd42387caf0d6835"}, - {file = "regex-2024.5.15-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c3bea0ba8b73b71b37ac833a7f3fd53825924165da6a924aec78c13032f20850"}, - {file = "regex-2024.5.15-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bfc4f82cabe54f1e7f206fd3d30fda143f84a63fe7d64a81558d6e5f2e5aaba9"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5bb9425fe881d578aeca0b2b4b3d314ec88738706f66f219c194d67179337cb"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64c65783e96e563103d641760664125e91bd85d8e49566ee560ded4da0d3e704"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf2430df4148b08fb4324b848672514b1385ae3807651f3567871f130a728cc3"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5397de3219a8b08ae9540c48f602996aa6b0b65d5a61683e233af8605c42b0f2"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:455705d34b4154a80ead722f4f185b04c4237e8e8e33f265cd0798d0e44825fa"}, - {file = "regex-2024.5.15-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b2b6f1b3bb6f640c1a92be3bbfbcb18657b125b99ecf141fb3310b5282c7d4ed"}, - {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3ad070b823ca5890cab606c940522d05d3d22395d432f4aaaf9d5b1653e47ced"}, - {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5b5467acbfc153847d5adb21e21e29847bcb5870e65c94c9206d20eb4e99a384"}, - {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e6662686aeb633ad65be2a42b4cb00178b3fbf7b91878f9446075c404ada552f"}, - {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:2b4c884767504c0e2401babe8b5b7aea9148680d2e157fa28f01529d1f7fcf67"}, - {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3cd7874d57f13bf70078f1ff02b8b0aa48d5b9ed25fc48547516c6aba36f5741"}, - {file = "regex-2024.5.15-cp38-cp38-win32.whl", hash = "sha256:e4682f5ba31f475d58884045c1a97a860a007d44938c4c0895f41d64481edbc9"}, - {file = "regex-2024.5.15-cp38-cp38-win_amd64.whl", hash = "sha256:d99ceffa25ac45d150e30bd9ed14ec6039f2aad0ffa6bb87a5936f5782fc1569"}, - {file = "regex-2024.5.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13cdaf31bed30a1e1c2453ef6015aa0983e1366fad2667657dbcac7b02f67133"}, - {file = "regex-2024.5.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cac27dcaa821ca271855a32188aa61d12decb6fe45ffe3e722401fe61e323cd1"}, - {file = "regex-2024.5.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7dbe2467273b875ea2de38ded4eba86cbcbc9a1a6d0aa11dcf7bd2e67859c435"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f18a9a3513a99c4bef0e3efd4c4a5b11228b48aa80743be822b71e132ae4f5"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d347a741ea871c2e278fde6c48f85136c96b8659b632fb57a7d1ce1872547600"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1878b8301ed011704aea4c806a3cadbd76f84dece1ec09cc9e4dc934cfa5d4da"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4babf07ad476aaf7830d77000874d7611704a7fcf68c9c2ad151f5d94ae4bfc4"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35cb514e137cb3488bce23352af3e12fb0dbedd1ee6e60da053c69fb1b29cc6c"}, - {file = "regex-2024.5.15-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cdd09d47c0b2efee9378679f8510ee6955d329424c659ab3c5e3a6edea696294"}, - {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:72d7a99cd6b8f958e85fc6ca5b37c4303294954eac1376535b03c2a43eb72629"}, - {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a094801d379ab20c2135529948cb84d417a2169b9bdceda2a36f5f10977ebc16"}, - {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c0c18345010870e58238790a6779a1219b4d97bd2e77e1140e8ee5d14df071aa"}, - {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:16093f563098448ff6b1fa68170e4acbef94e6b6a4e25e10eae8598bb1694b5d"}, - {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e38a7d4e8f633a33b4c7350fbd8bad3b70bf81439ac67ac38916c4a86b465456"}, - {file = "regex-2024.5.15-cp39-cp39-win32.whl", hash = "sha256:71a455a3c584a88f654b64feccc1e25876066c4f5ef26cd6dd711308aa538694"}, - {file = "regex-2024.5.15-cp39-cp39-win_amd64.whl", hash = "sha256:cab12877a9bdafde5500206d1020a584355a97884dfd388af3699e9137bf7388"}, - {file = "regex-2024.5.15.tar.gz", hash = "sha256:d3ee02d9e5f482cc8309134a91eeaacbdd2261ba111b0fef3748eeb4913e6a2c"}, + {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b0d3f567fafa0633aee87f08b9276c7062da9616931382993c03808bb68ce"}, + {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3426de3b91d1bc73249042742f45c2148803c111d1175b283270177fdf669024"}, + {file = "regex-2024.7.24-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f273674b445bcb6e4409bf8d1be67bc4b58e8b46fd0d560055d515b8830063cd"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23acc72f0f4e1a9e6e9843d6328177ae3074b4182167e34119ec7233dfeccf53"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65fd3d2e228cae024c411c5ccdffae4c315271eee4a8b839291f84f796b34eca"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c414cbda77dbf13c3bc88b073a1a9f375c7b0cb5e115e15d4b73ec3a2fbc6f59"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7a89eef64b5455835f5ed30254ec19bf41f7541cd94f266ab7cbd463f00c41"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19c65b00d42804e3fbea9708f0937d157e53429a39b7c61253ff15670ff62cb5"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7a5486ca56c8869070a966321d5ab416ff0f83f30e0e2da1ab48815c8d165d46"}, + {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f51f9556785e5a203713f5efd9c085b4a45aecd2a42573e2b5041881b588d1f"}, + {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a4997716674d36a82eab3e86f8fa77080a5d8d96a389a61ea1d0e3a94a582cf7"}, + {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c0abb5e4e8ce71a61d9446040c1e86d4e6d23f9097275c5bd49ed978755ff0fe"}, + {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:18300a1d78cf1290fa583cd8b7cde26ecb73e9f5916690cf9d42de569c89b1ce"}, + {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:416c0e4f56308f34cdb18c3f59849479dde5b19febdcd6e6fa4d04b6c31c9faa"}, + {file = "regex-2024.7.24-cp310-cp310-win32.whl", hash = "sha256:fb168b5924bef397b5ba13aabd8cf5df7d3d93f10218d7b925e360d436863f66"}, + {file = "regex-2024.7.24-cp310-cp310-win_amd64.whl", hash = "sha256:6b9fc7e9cc983e75e2518496ba1afc524227c163e43d706688a6bb9eca41617e"}, + {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281"}, + {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b"}, + {file = "regex-2024.7.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e"}, + {file = "regex-2024.7.24-cp311-cp311-win32.whl", hash = "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c"}, + {file = "regex-2024.7.24-cp311-cp311-win_amd64.whl", hash = "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52"}, + {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86"}, + {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad"}, + {file = "regex-2024.7.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38"}, + {file = "regex-2024.7.24-cp312-cp312-win32.whl", hash = "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc"}, + {file = "regex-2024.7.24-cp312-cp312-win_amd64.whl", hash = "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908"}, + {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:66b4c0731a5c81921e938dcf1a88e978264e26e6ac4ec96a4d21ae0354581ae0"}, + {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:88ecc3afd7e776967fa16c80f974cb79399ee8dc6c96423321d6f7d4b881c92b"}, + {file = "regex-2024.7.24-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64bd50cf16bcc54b274e20235bf8edbb64184a30e1e53873ff8d444e7ac656b2"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb462f0e346fcf41a901a126b50f8781e9a474d3927930f3490f38a6e73b6950"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a82465ebbc9b1c5c50738536fdfa7cab639a261a99b469c9d4c7dcbb2b3f1e57"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:68a8f8c046c6466ac61a36b65bb2395c74451df2ffb8458492ef49900efed293"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac8e84fff5d27420f3c1e879ce9929108e873667ec87e0c8eeb413a5311adfe"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba2537ef2163db9e6ccdbeb6f6424282ae4dea43177402152c67ef869cf3978b"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:43affe33137fcd679bdae93fb25924979517e011f9dea99163f80b82eadc7e53"}, + {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c9bb87fdf2ab2370f21e4d5636e5317775e5d51ff32ebff2cf389f71b9b13750"}, + {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:945352286a541406f99b2655c973852da7911b3f4264e010218bbc1cc73168f2"}, + {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:8bc593dcce679206b60a538c302d03c29b18e3d862609317cb560e18b66d10cf"}, + {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3f3b6ca8eae6d6c75a6cff525c8530c60e909a71a15e1b731723233331de4169"}, + {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c51edc3541e11fbe83f0c4d9412ef6c79f664a3745fab261457e84465ec9d5a8"}, + {file = "regex-2024.7.24-cp38-cp38-win32.whl", hash = "sha256:d0a07763776188b4db4c9c7fb1b8c494049f84659bb387b71c73bbc07f189e96"}, + {file = "regex-2024.7.24-cp38-cp38-win_amd64.whl", hash = "sha256:8fd5afd101dcf86a270d254364e0e8dddedebe6bd1ab9d5f732f274fa00499a5"}, + {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0ffe3f9d430cd37d8fa5632ff6fb36d5b24818c5c986893063b4e5bdb84cdf24"}, + {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25419b70ba00a16abc90ee5fce061228206173231f004437730b67ac77323f0d"}, + {file = "regex-2024.7.24-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:33e2614a7ce627f0cdf2ad104797d1f68342d967de3695678c0cb84f530709f8"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33a0021893ede5969876052796165bab6006559ab845fd7b515a30abdd990dc"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04ce29e2c5fedf296b1a1b0acc1724ba93a36fb14031f3abfb7abda2806c1535"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b16582783f44fbca6fcf46f61347340c787d7530d88b4d590a397a47583f31dd"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:836d3cc225b3e8a943d0b02633fb2f28a66e281290302a79df0e1eaa984ff7c1"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438d9f0f4bc64e8dea78274caa5af971ceff0f8771e1a2333620969936ba10be"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:973335b1624859cb0e52f96062a28aa18f3a5fc77a96e4a3d6d76e29811a0e6e"}, + {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c5e69fd3eb0b409432b537fe3c6f44ac089c458ab6b78dcec14478422879ec5f"}, + {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fbf8c2f00904eaf63ff37718eb13acf8e178cb940520e47b2f05027f5bb34ce3"}, + {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2757ace61bc4061b69af19e4689fa4416e1a04840f33b441034202b5cd02d4"}, + {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:44fc61b99035fd9b3b9453f1713234e5a7c92a04f3577252b45feefe1b327759"}, + {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:84c312cdf839e8b579f504afcd7b65f35d60b6285d892b19adea16355e8343c9"}, + {file = "regex-2024.7.24-cp39-cp39-win32.whl", hash = "sha256:ca5b2028c2f7af4e13fb9fc29b28d0ce767c38c7facdf64f6c2cd040413055f1"}, + {file = "regex-2024.7.24-cp39-cp39-win_amd64.whl", hash = "sha256:7c479f5ae937ec9985ecaf42e2e10631551d909f203e31308c12d703922742f9"}, + {file = "regex-2024.7.24.tar.gz", hash = "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506"}, ] [[package]] name = "requests" -version = "2.28.1" +version = "2.31.0" description = "Python HTTP for Humans." -category = "main" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.7" files = [ - {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, - {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, + {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,<3" +charset-normalizer = ">=2,<4" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" +urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] @@ -2835,7 +2817,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "requests-toolbelt" version = "1.0.0" description = "A utility belt for advanced users of python-requests" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2850,7 +2831,6 @@ requests = ">=2.0.1,<3.0.0" name = "rlp" version = "3.0.0" description = "A package for Recursive Length Prefix encoding and decoding" -category = "main" optional = false python-versions = "*" files = [ @@ -2872,7 +2852,6 @@ test = ["hypothesis (==5.19.0)", "pytest (>=6.2.5,<7)", "tox (>=2.9.1,<3)"] name = "semver" version = "2.13.0" description = "Python helper for Semantic Versioning (http://semver.org/)" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2882,25 +2861,24 @@ files = [ [[package]] name = "setuptools" -version = "70.2.0" +version = "71.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"}, - {file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"}, + {file = "setuptools-71.1.0-py3-none-any.whl", hash = "sha256:33874fdc59b3188304b2e7c80d9029097ea31627180896fb549c578ceb8a0855"}, + {file = "setuptools-71.1.0.tar.gz", hash = "sha256:032d42ee9fb536e33087fb66cac5f840eb9391ed05637b3f2a76a7c8fb477936"}, ] [package.extras] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -2912,7 +2890,6 @@ files = [ name = "sniffio" version = "1.3.1" description = "Sniff out which async library your code is running under" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2924,7 +2901,6 @@ files = [ name = "starlette" version = "0.36.3" description = "The little ASGI library that shines." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2943,7 +2919,6 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 name = "texttable" version = "1.6.7" description = "module to create simple ASCII tables" -category = "main" optional = false python-versions = "*" files = [ @@ -2955,7 +2930,6 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2965,34 +2939,33 @@ files = [ [[package]] name = "tomte" -version = "0.2.15" +version = "0.2.17" description = "A library that wraps many useful tools (linters, analysers, etc) to keep Python code clean, secure, well-documented and optimised." -category = "dev" optional = false -python-versions = ">=3.8,<4" +python-versions = "<4,>=3.8" files = [ - {file = "tomte-0.2.15-py3-none-any.whl", hash = "sha256:c1ec71bdb919290e42671d83098232bf7cf46cddf1a736c5d1c9f12ab1308c34"}, - {file = "tomte-0.2.15.tar.gz", hash = "sha256:662f3cdd616347969c3fea557c47545b555f5f82798b978e78ade3d23d43c92d"}, + {file = "tomte-0.2.17-py3-none-any.whl", hash = "sha256:477e1e903610b5e2a8cf74a78cf229eacc21aa666e25e7bb872385ef2c013cfe"}, + {file = "tomte-0.2.17.tar.gz", hash = "sha256:ad583dd39f2c398272f7f196471b2ecc8430eb89e07295ec1e682f64dd782831"}, ] [package.dependencies] -click = {version = "8.0.2", optional = true, markers = "extra == \"black\" or extra == \"cli\" or extra == \"docs\""} -requests = {version = "2.28.1", optional = true, markers = "extra == \"cli\""} +click = {version = ">=8.1.0,<9", optional = true, markers = "extra == \"black\" or extra == \"cli\" or extra == \"docs\""} +requests = {version = ">=2.28.1,<3", optional = true, markers = "extra == \"cli\""} tox = {version = "3.28.0", optional = true, markers = "extra == \"cli\" or extra == \"tox\""} [package.extras] bandit = ["bandit (==1.7.4)"] -black = ["black (==23.1.0)", "click (==8.0.2)"] -cli = ["click (==8.0.2)", "requests (==2.28.1)", "tox (==3.28.0)"] +black = ["black (==23.1.0)", "click (>=8.1.0,<9)"] +cli = ["click (>=8.1.0,<9)", "requests (>=2.28.1,<3)", "tox (==3.28.0)"] darglint = ["darglint (==1.8.1)"] -docs = ["Markdown (==3.3.7)", "Pygments (>=2.16,<3.0)", "bs4 (==0.0.1)", "click (==8.0.2)", "markdown-include (==0.8.0)", "mkdocs (>=1.5.3,<2.0)", "mkdocs-macros-plugin (==0.7.0)", "mkdocs-material (==9.4.10)", "mkdocs-material-extensions (==1.3)", "mkdocs-redirects (==1.2.0)", "pydoc-markdown (==4.8.2)", "pydocstyle (==6.2.3)", "pymdown-extensions (>=10.2,<11.0)"] +docs = ["Markdown (==3.3.7)", "Pygments (>=2.16,<3.0)", "bs4 (==0.0.1)", "click (>=8.1.0,<9)", "markdown-include (==0.8.0)", "mkdocs (>=1.5.3,<2.0)", "mkdocs-macros-plugin (==0.7.0)", "mkdocs-material (==9.4.10)", "mkdocs-material-extensions (==1.3)", "mkdocs-redirects (==1.2.0)", "pydoc-markdown (==4.8.2)", "pydocstyle (==6.2.3)", "pymdown-extensions (>=10.2,<11.0)"] flake8 = ["flake8 (==3.9.2)", "flake8-bugbear (==23.1.14)", "flake8-docstrings (==1.6.0)", "flake8-eradicate (==1.4.0)", "flake8-isort (==6.0.0)", "pydocstyle (==6.2.3)"] isort = ["isort (==5.11.4)"] liccheck = ["liccheck (==0.8.3)"] mypy = ["mypy (==0.991)"] pylint = ["pylint (==2.13.9)"] safety = ["safety (==2.4.0b1)"] -tests = ["pytest (==7.2.1)", "pytest-asyncio (==0.20.3)", "pytest-cov (==4.0.0)", "pytest-randomly (==3.12.0)", "pytest-rerunfailures (==11.0)"] +tests = ["pytest (==7.2.1)", "pytest-asyncio (>=0.21.0,<0.22.0)", "pytest-cov (==4.0.0)", "pytest-randomly (==3.12.0)", "pytest-rerunfailures (==11.0)"] tox = ["tox (==3.28.0)"] vulture = ["vulture (==2.7)"] @@ -3000,7 +2973,6 @@ vulture = ["vulture (==2.7)"] name = "toolz" version = "0.12.1" description = "List processing tools and functional utilities" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3012,7 +2984,6 @@ files = [ name = "tox" version = "3.28.0" description = "tox is a generic virtualenv management and test command line tool" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -3038,7 +3009,6 @@ testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "psu name = "typing-extensions" version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3048,26 +3018,25 @@ files = [ [[package]] name = "urllib3" -version = "1.26.19" +version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, - {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] -brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" version = "0.27.0" description = "The lightning-fast ASGI server." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3087,7 +3056,6 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", name = "valory-docker-compose" version = "1.29.3" description = "Multi-container orchestration for Docker" -category = "main" optional = false python-versions = ">=3.4" files = [ @@ -3116,7 +3084,6 @@ tests = ["ddt (>=1.2.2,<2)", "pytest (<6)"] name = "varint" version = "1.0.2" description = "Simple python varint implementation" -category = "main" optional = false python-versions = "*" files = [ @@ -3127,7 +3094,6 @@ files = [ name = "virtualenv" version = "20.26.3" description = "Virtual Python Environment builder" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3148,7 +3114,6 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess name = "watchdog" version = "4.0.1" description = "Filesystem events monitoring" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3193,7 +3158,6 @@ watchmedo = ["PyYAML (>=3.10)"] name = "web3" version = "6.1.0" description = "web3.py" -category = "main" optional = false python-versions = ">=3.7.2" files = [ @@ -3227,7 +3191,6 @@ tester = ["eth-tester[py-evm] (==v0.8.0-b.3)", "py-geth (>=3.11.0)"] name = "websocket-client" version = "0.59.0" description = "WebSocket client for Python with low level API options" -category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -3242,7 +3205,6 @@ six = "*" name = "websockets" version = "12.0" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3324,7 +3286,6 @@ files = [ name = "werkzeug" version = "2.0.3" description = "The comprehensive WSGI web application library." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -3339,7 +3300,6 @@ watchdog = ["watchdog"] name = "yarl" version = "1.9.4" description = "Yet another URL library" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3443,7 +3403,6 @@ multidict = ">=4.0" name = "zipp" version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -3458,4 +3417,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "<3.12,>=3.9" -content-hash = "456a1a45f86bdda8fcc8c9e922c0eec5d129707d2354ac29985bec3fc7b94842" +content-hash = "85568473089af1d5ba1b5a8ada225c96b7ff03067a2edabdaacd7ff61e4d0a06" diff --git a/pyproject.toml b/pyproject.toml index a0821d0a9..a7bfc85fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,11 +19,11 @@ operate = "operate.cli:main" [tool.poetry.dependencies] python = "<3.12,>=3.9" -open-autonomy = "==0.14.11.post1" -open-aea-ledger-cosmos = "==1.51.0" -open-aea-ledger-ethereum = "==1.51.0" -open-aea-ledger-ethereum-flashbots = "==1.51.0" -open-aea-cli-ipfs = "==1.51.0" +open-autonomy = "==0.14.14.post2" +open-aea-ledger-cosmos = "==1.53.0" +open-aea-ledger-ethereum = "==1.53.0" +open-aea-ledger-ethereum-flashbots = "==1.53.0" +open-aea-cli-ipfs = "==1.53.0" clea = "==0.1.0rc4" cytoolz = "==0.12.3" docker = "6.1.2" @@ -50,7 +50,7 @@ pyinstaller = "^6.8.0" aiohttp = "3.9.5" [tool.poetry.group.development.dependencies] -tomte = {version = "0.2.15", extras = ["cli"]} +tomte = {version = "0.2.17", extras = ["cli"]} [build-system] requires = ["poetry-core"] From e096a81ffeff2df53114ce4ed392e03f8a520d85 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Fri, 26 Jul 2024 13:46:49 +0200 Subject: [PATCH 05/99] chore: fix --- operate/services/manage.py | 18 ++++++++++-------- operate/types.py | 11 ----------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index e8d452728..21069148d 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -369,6 +369,7 @@ def deploy_service_onchain( # pylint: disable=too-many-statements def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too-many-locals self, hash: str, + update: bool = False, ) -> None: """ Deploy as service on-chain @@ -427,7 +428,6 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too f"address: {wallet.safe}; required olas: {required_olas}; your balance: {balance}" ) - on_chain_hash = self._get_on_chain_hash(service) is_first_mint = self._get_on_chain_state(service) == OnChainState.NON_EXISTENT is_update = (not is_first_mint) and (on_chain_hash is not None) and (on_chain_hash != service.hash) @@ -436,15 +436,17 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too self.logger.info(f"{is_first_mint=}") self.logger.info(f"{is_update=}") - if is_update: - self.terminate_service_on_chain_from_safe(hash=hash) + is_update = update # TODO fix + # if is_update: + # self.terminate_service_on_chain_from_safe(hash=hash) - if is_first_mint or (is_update and self._get_on_chain_state(service) == OnChainState.PRE_REGISTRATION): - if not is_update: - self.logger.info("Minting the on-chain service") - else: - self.logger.info("Updating the on-chain service") + # if is_first_mint or (is_update and self._get_on_chain_state(service) == OnChainState.PRE_REGISTRATION): + # if not is_update: + # self.logger.info("Minting the on-chain service") + # else: + # self.logger.info("Updating the on-chain service") + if is_first_mint: receipt = ( sftxb.new_tx() .add( diff --git a/operate/types.py b/operate/types.py index 1babb5f82..efd3e8cf7 100644 --- a/operate/types.py +++ b/operate/types.py @@ -166,17 +166,6 @@ class LedgerConfig(LocalResource): LedgerConfigs = t.List[LedgerConfig] -class ServiceState(enum.IntEnum): - """Service state""" - - NON_EXISTENT = 0 - PRE_REGISTRATION = 1 - ACTIVE_REGISTRATION = 2 - FINISHED_REGISTRATION = 3 - DEPLOYED = 4 - TERMINATED_BONDED = 5 - - class DeploymentConfig(TypedDict): """Deployments template.""" From 6bcd92ffe1b04d5c88681d96436d9e5b12b04c99 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Fri, 26 Jul 2024 18:49:45 +0200 Subject: [PATCH 06/99] [no ci] chore: update --- operate/cli.py | 12 ++++-------- operate/services/manage.py | 18 +++++++++--------- operate/services/service.py | 10 ++++++---- operate/types.py | 24 ++++++++++++++++++++---- 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index 80dfa36bf..feaad20ad 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -515,12 +515,10 @@ async def _create_services(request: Request) -> JSONResponse: old_hash = manager.json[0]["hash"] if old_hash == template["hash"]: logger.info(f'Loading service {template["hash"]}') + chain_configs = [services.manage.ChainConfig.from_json(item) for item in template["chain_configs"]] service = manager.load_or_create( hash=template["hash"], - rpc=template["configuration"]["rpc"], - on_chain_user_params=services.manage.OnChainUserParams.from_json( - template["configuration"] - ), + chain_configs=chain_configs, ) else: logger.info(f"Updating service from {old_hash} to " + template["hash"]) @@ -536,12 +534,10 @@ async def _create_services(request: Request) -> JSONResponse: update = True else: logger.info(f'Creating service {template["hash"]}') + chain_configs = [services.manage.ChainConfig.from_json(item) for item in template["chain_configs"]] service = manager.load_or_create( hash=template["hash"], - rpc=template["configuration"]["rpc"], - on_chain_user_params=services.manage.OnChainUserParams.from_json( - template["configuration"] - ), + chain_configs=chain_configs, ) if template.get("deploy", False): diff --git a/operate/services/manage.py b/operate/services/manage.py index 21069148d..431ec8d87 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -38,6 +38,8 @@ from operate.ledger.profiles import CONTRACTS, OLAS, STAKING from operate.services.protocol import EthSafeTxBuilder, OnChainManager, StakingState from operate.services.service import ( + ChainConfig, + ChainConfigs, DELETE_PREFIX, Deployment, NON_EXISTENT_TOKEN, @@ -142,8 +144,7 @@ def get_eth_safe_tx_builder(self, service: Service) -> EthSafeTxBuilder: def load_or_create( self, hash: str, - rpc: t.Optional[str] = None, - on_chain_user_params: t.Optional[OnChainUserParams] = None, + chain_configs: t.Optional[ChainConfigs] = None, keys: t.Optional[t.List[Key]] = None, ) -> Service: """ @@ -151,7 +152,7 @@ def load_or_create( :param hash: Service hash :param rpc: RPC string - :param on_chain_user_params: On-chain user parameters + :param chain_configs: Chain configurations :param keys: Keys :return: Service instance """ @@ -159,20 +160,19 @@ def load_or_create( if path.exists(): return Service.load(path=path) - if rpc is None: - raise ValueError("RPC cannot be None when creating a new service") + # if rpc is None: + # raise ValueError("RPC cannot be None when creating a new service") - if on_chain_user_params is None: + if chain_configs is None: raise ValueError( - "On-chain user parameters cannot be None when creating a new service" + "Chain configurations cannot be None when creating a new service" ) service = Service.new( hash=hash, keys=keys or [], - rpc=rpc, storage=self.path, - on_chain_user_params=on_chain_user_params, + chain_configs=chain_configs, ) if not service.keys: diff --git a/operate/services/service.py b/operate/services/service.py index 67121bb44..1d0624575 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -67,6 +67,8 @@ from operate.services.utils import tendermint from operate.types import ( ChainType, + ChainConfig, + ChainConfigs, DeployedNodes, DeploymentConfig, DeploymentStatus, @@ -625,8 +627,7 @@ class Service(LocalResource): hash: str keys: Keys - ledger_config: LedgerConfig - chain_data: OnChainData + chain_configs: ChainConfigs path: Path service_path: Path @@ -663,8 +664,7 @@ def deployment(self) -> Deployment: def new( hash: str, keys: Keys, - rpc: str, - on_chain_user_params: OnChainUserParams, + chain_configs: ChainConfigs, storage: Path, ) -> "Service": """Create a new service.""" @@ -680,6 +680,8 @@ def new( config, *_ = yaml_load_all(fp) ledger_config = ServiceHelper(path=service_path).ledger_config() + + ledger_config.chain service = Service( name=config["author"] + "/" + config["name"], hash=hash, diff --git a/operate/types.py b/operate/types.py index efd3e8cf7..8b3887d82 100644 --- a/operate/types.py +++ b/operate/types.py @@ -163,9 +163,6 @@ class LedgerConfig(LocalResource): chain: ChainType -LedgerConfigs = t.List[LedgerConfig] - - class DeploymentConfig(TypedDict): """Deployments template.""" @@ -193,6 +190,9 @@ class ConfigurationTemplate(TypedDict): fund_requirements: FundRequirementsTemplate +ConfigurationTemplates = t.List[ConfigurationTemplate] + + class ServiceTemplate(TypedDict): """Service template.""" @@ -200,7 +200,7 @@ class ServiceTemplate(TypedDict): hash: str image: str description: str - configuration: ConfigurationTemplate + configurations: ConfigurationTemplates @dataclass @@ -248,3 +248,19 @@ class OnChainData(LocalResource): staked: bool on_chain_state: OnChainState user_params: OnChainUserParams + + +@dataclass +class ChainConfig(LocalResource): + """Chain config.""" + + ledger_config: LedgerConfig + chain_data: OnChainData + + @classmethod + def from_json(cls, obj: t.Dict) -> "ChainConfig": + """Load the chain config.""" + return super().from_json(obj) # type: ignore + + +ChainConfigs = t.List[ChainConfig] From 403aa589ba64b9f6fde66d07a7fd1a133ad77e9a Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Fri, 2 Aug 2024 17:07:05 +0200 Subject: [PATCH 07/99] chore: refactor --- operate/cli.py | 10 ++++- operate/services/manage.py | 90 +++++++++++++++++++++++-------------- operate/services/service.py | 68 +++++++++++++++++----------- operate/types.py | 9 +++- 4 files changed, 114 insertions(+), 63 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index feaad20ad..44fe5b279 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -515,7 +515,10 @@ async def _create_services(request: Request) -> JSONResponse: old_hash = manager.json[0]["hash"] if old_hash == template["hash"]: logger.info(f'Loading service {template["hash"]}') - chain_configs = [services.manage.ChainConfig.from_json(item) for item in template["chain_configs"]] + chain_configs = [ + services.manage.ChainConfig.from_json(item) + for item in template["chain_configs"] + ] service = manager.load_or_create( hash=template["hash"], chain_configs=chain_configs, @@ -534,7 +537,10 @@ async def _create_services(request: Request) -> JSONResponse: update = True else: logger.info(f'Creating service {template["hash"]}') - chain_configs = [services.manage.ChainConfig.from_json(item) for item in template["chain_configs"]] + chain_configs = [ + services.manage.ChainConfig.from_json(item) + for item in template["chain_configs"] + ] service = manager.load_or_create( hash=template["hash"], chain_configs=chain_configs, diff --git a/operate/services/manage.py b/operate/services/manage.py index 431ec8d87..b036f2a9d 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -48,6 +48,7 @@ OnChainUserParams, Service, ) +from operate.types import ServiceTemplate from operate.wallet.master import MasterWalletManager @@ -144,15 +145,14 @@ def get_eth_safe_tx_builder(self, service: Service) -> EthSafeTxBuilder: def load_or_create( self, hash: str, - chain_configs: t.Optional[ChainConfigs] = None, + service_template: t.Optional[ServiceTemplate] = None, keys: t.Optional[t.List[Key]] = None, ) -> Service: """ Create or load a service :param hash: Service hash - :param rpc: RPC string - :param chain_configs: Chain configurations + :param service_template: Service template :param keys: Keys :return: Service instance """ @@ -160,19 +160,16 @@ def load_or_create( if path.exists(): return Service.load(path=path) - # if rpc is None: - # raise ValueError("RPC cannot be None when creating a new service") - - if chain_configs is None: + if service_template is None: raise ValueError( - "Chain configurations cannot be None when creating a new service" + "'service_template' cannot be None when creating a new service" ) service = Service.new( hash=hash, keys=keys or [], storage=self.path, - chain_configs=chain_configs, + service_template=service_template, ) if not service.keys: @@ -198,7 +195,6 @@ def _get_on_chain_state(self, service: Service) -> OnChainState: service.store() return service_state - def _get_on_chain_hash(self, service: Service) -> t.Optional[str]: if service.chain_data.token == NON_EXISTENT_TOKEN: return None @@ -366,10 +362,25 @@ def deploy_service_onchain( # pylint: disable=too-many-statements ) service.store() + def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too-many-locals self, hash: str, update: bool = False, + ) -> None: + service = self.load_or_create(hash=hash) + for chain_id in service.chain_configs.keys(): + self._deploy_service_onchain_from_safe( + hash=hash, + update=update, + chain_id=chain_id, + ) + + def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too-many-locals + self, + hash: str, + update: bool, + chain_id: int, ) -> None: """ Deploy as service on-chain @@ -380,36 +391,39 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too self.logger.info("Loading service") service = self.load_or_create(hash=hash) - user_params = service.chain_data.user_params + chain_config = service.chain_configs[chain_id] + ledger_config = chain_config.ledger_config + chain_data = chain_config.chain_data + user_params = chain_config.chain_data.user_params keys = service.keys instances = [key.address for key in keys] - wallet = self.wallet_manager.load(service.ledger_config.type) + wallet = self.wallet_manager.load(ledger_config.type) sftxb = self.get_eth_safe_tx_builder(service=service) if user_params.use_staking and not sftxb.staking_slots_available( - staking_contract=STAKING[service.ledger_config.chain] + staking_contract=STAKING[ledger_config.chain] ): raise ValueError("No staking slots available") - if service.chain_data.token > -1: + if chain_data.token > -1: self.logger.info("Syncing service state") - info = sftxb.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) - service.chain_data.instances = info["instances"] - service.chain_data.multisig = info["multisig"] + info = sftxb.info(token_id=chain_data.token) + chain_data.on_chain_state = OnChainState(info["service_state"]) + chain_data.instances = info["instances"] + chain_data.multisig = info["multisig"] service.store() self.logger.info(f"Service state: {service.chain_data.on_chain_state.name}") if user_params.use_staking: self.logger.info("Checking staking compatibility") - if service.chain_data.on_chain_state in ( + if chain_data.on_chain_state in ( OnChainState.NON_EXISTENT, OnChainState.PRE_REGISTRATION, ): required_olas = ( user_params.olas_cost_of_bond + user_params.olas_required_to_stake ) - elif service.chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: + elif chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: required_olas = user_params.olas_required_to_stake else: required_olas = 0 @@ -417,7 +431,7 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too balance = ( registry_contracts.erc20.get_instance( ledger_api=sftxb.ledger_api, - contract_address=OLAS[service.ledger_config.chain], + contract_address=OLAS[ledger_config.chain], ) .functions.balanceOf(wallet.safe) .call() @@ -430,7 +444,11 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too on_chain_hash = self._get_on_chain_hash(service) is_first_mint = self._get_on_chain_state(service) == OnChainState.NON_EXISTENT - is_update = (not is_first_mint) and (on_chain_hash is not None) and (on_chain_hash != service.hash) + is_update = ( + (not is_first_mint) + and (on_chain_hash is not None) + and (on_chain_hash != service.hash) + ) self.logger.info(f"{on_chain_hash=}") self.logger.info(f"{is_first_mint=}") @@ -446,7 +464,7 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too # else: # self.logger.info("Updating the on-chain service") - if is_first_mint: + if self._get_on_chain_state(service) == OnChainState.NON_EXISTENT: receipt = ( sftxb.new_tx() .add( @@ -461,9 +479,9 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too ), threshold=user_params.threshold, nft=IPFSHash(user_params.nft), - update_token=service.chain_data.token if is_update else None, + update_token=chain_data.token if update else None, token=( - OLAS[service.ledger_config.chain] + OLAS[ledger_config.chain] if user_params.use_staking else None ), @@ -480,10 +498,12 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too receipt=receipt, ).get("events"), ) - service.chain_data.token = event_data["args"]["serviceId"] - service.chain_data.on_chain_state = OnChainState.PRE_REGISTRATION + chain_data.token = event_data["args"]["serviceId"] + chain_data.on_chain_state = OnChainState.PRE_REGISTRATION service.store() + + print("!!!!!!!!!!!!!!!!!!!!!") if self._get_on_chain_state(service) == OnChainState.PRE_REGISTRATION: cost_of_bond = user_params.cost_of_bond if user_params.use_staking: @@ -597,7 +617,6 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too service.chain_data.on_chain_state = OnChainState.DEPLOYED service.store() - # Update local Service info = sftxb.info(token_id=service.chain_data.token) service.chain_data = OnChainData( @@ -649,12 +668,19 @@ def terminate_service_on_chain_from_safe(self, hash: str) -> None: info = sftxb.info(token_id=service.chain_data.token) service.chain_data.on_chain_state = OnChainState(info["service_state"]) - if service.chain_data.user_params.use_staking and not self._can_unstake_service(hash=hash): + if ( + service.chain_data.user_params.use_staking + and not self._can_unstake_service(hash=hash) + ): return self.unstake_service_on_chain(hash=hash) - if self._get_on_chain_state(service) in (OnChainState.ACTIVE_REGISTRATION, OnChainState.FINISHED_REGISTRATION, OnChainState.DEPLOYED): + if self._get_on_chain_state(service) in ( + OnChainState.ACTIVE_REGISTRATION, + OnChainState.FINISHED_REGISTRATION, + OnChainState.DEPLOYED, + ): self.logger.info("Terminating service") sftxb.new_tx().add( sftxb.get_terminate_data( @@ -670,8 +696,7 @@ def terminate_service_on_chain_from_safe(self, hash: str) -> None: ) ).settle() - - if [[ "$current_safe_owners" == "['$agent_address']" ]]: + if [["$current_safe_owners" == "['$agent_address']"]]: sftx = self.get_eth_safe_tx_builder(service=old_service) # noqa: E800 sftx.swap( # noqa: E800 service_id=old_service.chain_data.token, # noqa: E800 @@ -681,7 +706,6 @@ def terminate_service_on_chain_from_safe(self, hash: str) -> None: ), # noqa: E800 ) # noqa: E800 - def unbond_service_on_chain(self, hash: str) -> None: """ Unbond service on-chain diff --git a/operate/services/service.py b/operate/services/service.py index 1d0624575..3c36e4050 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -66,17 +66,21 @@ from operate.services.deployment_runner import run_host_deployment, stop_host_deployment from operate.services.utils import tendermint from operate.types import ( - ChainType, ChainConfig, ChainConfigs, + ChainType, + ConfigurationTemplate, + ConfigurationTemplates, DeployedNodes, DeploymentConfig, DeploymentStatus, LedgerConfig, + LedgerConfigs, LedgerType, OnChainData, OnChainState, OnChainUserParams, + ServiceTemplate, ) @@ -236,21 +240,23 @@ def __init__(self, path: Path) -> None: self.path = path self.config = load_service_config(service_path=path) - def ledger_config(self) -> "LedgerConfig": - """Get ledger config.""" - # TODO: Multiledger/Multiagent support + def ledger_configs(self) -> "LedgerConfigs": + """Get ledger configs.""" + ledger_configs = {} for override in self.config.overrides: if ( override["type"] == "connection" and "valory/ledger" in override["public_id"] ): (_, config), *_ = override["config"]["ledger_apis"].items() - return LedgerConfig( + # TODO chain name is inferred from the chain_id. The actual id provided on service.yaml is ignored. + chain = ChainType.from_id(cid=config["chain_id"]) + ledger_configs[config["chain_id"]] = LedgerConfig( rpc=config["address"], - chain=ChainType.from_id(cid=config["chain_id"]), + chain=chain, type=LedgerType.ETHEREUM, ) - raise ValueError("No ledger config found.") + return ledger_configs def deployment_config(self) -> DeploymentConfig: """Returns deployment config.""" @@ -411,10 +417,12 @@ def _build_docker( ) builder.deplopyment_type = DockerComposeGenerator.deployment_type builder.try_update_abci_connection_params() + + home_chain_data = service.chain_configs[service.home_chain_id] builder.try_update_runtime_params( - multisig_address=service.chain_data.multisig, - agent_instances=service.chain_data.instances, - service_id=service.chain_data.token, + multisig_address=home_chain_data.multisig, + agent_instances=home_chain_data.instances, + service_id=home_chain_data.token, consensus_threshold=None, ) # TODO: Support for multiledger @@ -627,6 +635,7 @@ class Service(LocalResource): hash: str keys: Keys + home_chain_id: int chain_configs: ChainConfigs path: Path @@ -664,7 +673,7 @@ def deployment(self) -> Deployment: def new( hash: str, keys: Keys, - chain_configs: ChainConfigs, + service_template: ServiceTemplate, storage: Path, ) -> "Service": """Create a new service.""" @@ -677,28 +686,35 @@ def new( ) ) with (service_path / "service.yaml").open("r", encoding="utf-8") as fp: - config, *_ = yaml_load_all(fp) + service_yaml, *_ = yaml_load_all(fp) - ledger_config = ServiceHelper(path=service_path).ledger_config() + ledger_configs = ServiceHelper(path=service_path).ledger_configs() - ledger_config.chain - service = Service( - name=config["author"] + "/" + config["name"], - hash=hash, - keys=keys, - ledger_config=LedgerConfig( - rpc=rpc, - type=ledger_config.type, - chain=ledger_config.chain, - ), - chain_data=OnChainData( + chain_configs = {} + for chain, config in service_template["configurations"].items(): + ledger_config = ledger_configs[chain] + ledger_config.rpc = config["rpc"] + + chain_data = OnChainData( instances=[], token=NON_EXISTENT_TOKEN, multisig=DUMMY_MULTISIG, staked=False, on_chain_state=OnChainState.NON_EXISTENT, - user_params=on_chain_user_params, - ), + user_params=OnChainUserParams.from_json(config), + ) + + chain_configs[chain] = ChainConfig( + ledger_config=ledger_config, + chain_data=chain_data, + ) + + service = Service( + name=service_yaml["author"] + "/" + service_yaml["name"], + hash=service_template["hash"], + keys=keys, + home_chain_id=service_template["home_chain_id"], + chain_configs=chain_configs, path=service_path.parent, service_path=service_path, ) diff --git a/operate/types.py b/operate/types.py index 8b3887d82..a622d57c0 100644 --- a/operate/types.py +++ b/operate/types.py @@ -163,6 +163,9 @@ class LedgerConfig(LocalResource): chain: ChainType +LedgerConfigs = t.Dict[str, LedgerConfig] + + class DeploymentConfig(TypedDict): """Deployments template.""" @@ -190,7 +193,7 @@ class ConfigurationTemplate(TypedDict): fund_requirements: FundRequirementsTemplate -ConfigurationTemplates = t.List[ConfigurationTemplate] +ConfigurationTemplates = t.Dict[int, ConfigurationTemplate] class ServiceTemplate(TypedDict): @@ -200,6 +203,8 @@ class ServiceTemplate(TypedDict): hash: str image: str description: str + service_version: str + home_chain_id: int configurations: ConfigurationTemplates @@ -263,4 +268,4 @@ def from_json(cls, obj: t.Dict) -> "ChainConfig": return super().from_json(obj) # type: ignore -ChainConfigs = t.List[ChainConfig] +ChainConfigs = t.Dict[int, ChainConfig] From ca92d60b2190e39800094b37a8c6e30829fc2170 Mon Sep 17 00:00:00 2001 From: truemiller Date: Mon, 12 Aug 2024 21:46:51 +0100 Subject: [PATCH 08/99] feat: Add IncentiveProgramStatus enum and update PageState enum --- frontend/components/Alert/AlertTitle.tsx | 5 + .../IncentiveProgramBadge.tsx | 18 +++ .../IncentiveProgramSection/index.tsx | 131 ++++++++++++++++++ .../Incentives/WhatAreIncentivePrograms.tsx | 15 ++ frontend/components/Incentives/index.tsx | 62 +++++++++ frontend/components/Main/MainNeedsFunds.tsx | 3 +- .../components/Main/NewIncentiveAlert.tsx | 35 +++++ frontend/enums/IcentiveProgram.ts | 5 + frontend/enums/PageState.ts | 1 + frontend/types/IncentiveProgram.ts | 11 ++ 10 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 frontend/components/Alert/AlertTitle.tsx create mode 100644 frontend/components/Incentives/IncentiveProgramSection/IncentiveProgramBadge.tsx create mode 100644 frontend/components/Incentives/IncentiveProgramSection/index.tsx create mode 100644 frontend/components/Incentives/WhatAreIncentivePrograms.tsx create mode 100644 frontend/components/Incentives/index.tsx create mode 100644 frontend/components/Main/NewIncentiveAlert.tsx create mode 100644 frontend/enums/IcentiveProgram.ts create mode 100644 frontend/types/IncentiveProgram.ts diff --git a/frontend/components/Alert/AlertTitle.tsx b/frontend/components/Alert/AlertTitle.tsx new file mode 100644 index 000000000..5afecb32f --- /dev/null +++ b/frontend/components/Alert/AlertTitle.tsx @@ -0,0 +1,5 @@ +import { Typography } from 'antd'; + +export const AlertTitle = ({ children }: { children: React.ReactNode }) => ( + {children} +); diff --git a/frontend/components/Incentives/IncentiveProgramSection/IncentiveProgramBadge.tsx b/frontend/components/Incentives/IncentiveProgramSection/IncentiveProgramBadge.tsx new file mode 100644 index 000000000..c30882a18 --- /dev/null +++ b/frontend/components/Incentives/IncentiveProgramSection/IncentiveProgramBadge.tsx @@ -0,0 +1,18 @@ +import { Tag } from 'antd'; + +import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; + +export const IncentiveProgramTag = ({ + programStatus, +}: { + programStatus: IncentiveProgramStatus; +}) => { + if (programStatus === IncentiveProgramStatus.New) { + return New; + } else if (programStatus === IncentiveProgramStatus.Selected) { + return Selected; + } else if (programStatus === IncentiveProgramStatus.Deprecated) { + return Deprecated; + } + return null; +}; diff --git a/frontend/components/Incentives/IncentiveProgramSection/index.tsx b/frontend/components/Incentives/IncentiveProgramSection/index.tsx new file mode 100644 index 000000000..c11fcd452 --- /dev/null +++ b/frontend/components/Incentives/IncentiveProgramSection/index.tsx @@ -0,0 +1,131 @@ +import { Button, Flex, Typography } from 'antd'; + +import { Alert } from '@/components/Alert'; +import { AlertTitle } from '@/components/Alert/AlertTitle'; +import { CardSection } from '@/components/styled/CardSection'; +import { UNICODE_SYMBOLS } from '@/constants/symbols'; +import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; +import { useBalance } from '@/hooks/useBalance'; +import { Address } from '@/types/Address'; +import { IncentiveProgram } from '@/types/IncentiveProgram'; + +import { IncentiveProgramTag } from './IncentiveProgramBadge'; + +const ProgramTitle = ({ + name, + status, +}: { + name: string; + status: IncentiveProgramStatus; +}) => ( + + {name} + + +); + +const ProgramDetailsLink = ({ address }: { address: Address }) => { + const blockExplorerLink = `https://blockExplorer.com/poa/xdai/address/${address}`; + return ( + + Contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} + + ); +}; + +const HorizontalGreyLine = () => ( + +); + +export const IncentiveProgramSection = ({ + program, +}: { + program: IncentiveProgram; +}) => { + const { totalOlasBalance, totalEthBalance } = useBalance(); + return ( + + {/* Title */} + + + + + {/* Rewards per work period */} + + Rewards per work period + + {`0.25 OLAS`} + + {/* Required Olas */} + + Required OLAS for staking + + {`0.25 OLAS`} + + {/* Funding alert */} + + Insufficient amount of funds to switch + + Add funds to your account to meet the program requirements. + + + Your current OLAS balance: {totalOlasBalance} OLAS + + + Your current trading balance: {totalEthBalance} XDAI + + + } + /> + {/* No jobs available alert */} + + + No jobs currently available – try again later. + + + } + /> + {/* App update required */} + + App update required + + This incentive program is available for users who have the app + version rc105 or higher. + + Current app version: rc97 + {/* TODO: trigger update through IPC */} + + Update Pearl to the latest version {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + } + /> + {/* Switch to program button */} + + + ); +}; diff --git a/frontend/components/Incentives/WhatAreIncentivePrograms.tsx b/frontend/components/Incentives/WhatAreIncentivePrograms.tsx new file mode 100644 index 000000000..3fd179058 --- /dev/null +++ b/frontend/components/Incentives/WhatAreIncentivePrograms.tsx @@ -0,0 +1,15 @@ +import { RightOutlined } from '@ant-design/icons'; +import { Flex, Typography } from 'antd'; + +import { CardSection } from '../styled/CardSection'; + +export const WhatAreIncentiveProgramsSection = () => { + return ( + + + + What are incentive programs? + + + ); +}; diff --git a/frontend/components/Incentives/index.tsx b/frontend/components/Incentives/index.tsx new file mode 100644 index 000000000..11d998bcf --- /dev/null +++ b/frontend/components/Incentives/index.tsx @@ -0,0 +1,62 @@ +import { CloseOutlined, SettingOutlined } from '@ant-design/icons'; +import { Button, Card, Flex } from 'antd'; + +import { PageState } from '@/enums/PageState'; +import { usePageState } from '@/hooks/usePageState'; +import { IncentiveProgram } from '@/types/IncentiveProgram'; + +import { CardTitle } from '../Card/CardTitle'; +import { IncentiveProgramSection } from './IncentiveProgramSection'; +import { WhatAreIncentiveProgramsSection } from './WhatAreIncentivePrograms'; + +const IncentivesTitle = () => { + return ( + + + Settings + + } + /> + ); +}; + +const mockIncentivePrograms: IncentiveProgram[] = [ + { + name: 'Incentive Program 1', + rewardsPerWorkPeriod: 100, + requiredOlasForStaking: 1000, + contractAddress: '0x1234567890', + }, + { + name: 'Incentive Program 2', + rewardsPerWorkPeriod: 200, + requiredOlasForStaking: 2000, + contractAddress: '0x0987654321', + }, +]; + +export const Incentives = () => { + const { goto } = usePageState(); + return ( + } + extra={ + + + } + /> + + ); +}; diff --git a/frontend/enums/IcentiveProgram.ts b/frontend/enums/IcentiveProgram.ts new file mode 100644 index 000000000..f0351765a --- /dev/null +++ b/frontend/enums/IcentiveProgram.ts @@ -0,0 +1,5 @@ +export enum IncentiveProgramStatus { + New = 'new', + Selected = 'current', + Deprecated = 'deprecated', +} diff --git a/frontend/enums/PageState.ts b/frontend/enums/PageState.ts index 7a670f683..5a35793f0 100644 --- a/frontend/enums/PageState.ts +++ b/frontend/enums/PageState.ts @@ -5,4 +5,5 @@ export enum PageState { HelpAndSupport, Receive, Send, + MainIncentiveProgram, } diff --git a/frontend/types/IncentiveProgram.ts b/frontend/types/IncentiveProgram.ts new file mode 100644 index 000000000..4c04a97fe --- /dev/null +++ b/frontend/types/IncentiveProgram.ts @@ -0,0 +1,11 @@ +import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; + +import { Address } from './Address'; + +export type IncentiveProgram = { + name: string; + rewardsPerWorkPeriod: number; + requiredOlasForStaking: number; + status: IncentiveProgramStatus; + contractAddress: Address; +}; From c4884ab2e578b5e92933fbca058a1c98b6d769c7 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 13 Aug 2024 10:14:59 +0200 Subject: [PATCH 09/99] chore: update --- .../data/contracts/staking_token/__init__.py | 20 ++ .../data/contracts/staking_token/contract.py | 192 ++++++++++++++++++ .../contracts/staking_token/contract.yaml | 23 +++ operate/ledger/profiles.py | 17 +- operate/services/manage.py | 142 ++++++++----- operate/services/protocol.py | 60 +++++- operate/services/service.py | 2 +- operate/types.py | 4 +- 8 files changed, 396 insertions(+), 64 deletions(-) create mode 100644 operate/data/contracts/staking_token/__init__.py create mode 100644 operate/data/contracts/staking_token/contract.py create mode 100644 operate/data/contracts/staking_token/contract.yaml diff --git a/operate/data/contracts/staking_token/__init__.py b/operate/data/contracts/staking_token/__init__.py new file mode 100644 index 000000000..4682f8155 --- /dev/null +++ b/operate/data/contracts/staking_token/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the support resources for the staking contract.""" diff --git a/operate/data/contracts/staking_token/contract.py b/operate/data/contracts/staking_token/contract.py new file mode 100644 index 000000000..384beea7a --- /dev/null +++ b/operate/data/contracts/staking_token/contract.py @@ -0,0 +1,192 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023-2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the class to connect to the `ServiceStakingTokenMechUsage` contract.""" + +from enum import Enum + +from aea.common import JSONLike +from aea.configurations.base import PublicId +from aea.contracts.base import Contract +from aea.crypto.base import LedgerApi + + +class StakingTokenContract(Contract): + """The Service Staking contract.""" + + contract_id = PublicId.from_str("valory/staking_token:0.1.0") + + @classmethod + def get_service_staking_state( + cls, + ledger_api: LedgerApi, + contract_address: str, + service_id: int, + ) -> JSONLike: + """Check whether the service is staked.""" + contract_instance = cls.get_instance(ledger_api, contract_address) + res = contract_instance.functions.getStakingState(service_id).call() + return dict(data=res) + + @classmethod + def build_stake_tx( + cls, + ledger_api: LedgerApi, + contract_address: str, + service_id: int, + ) -> JSONLike: + """Build stake tx.""" + contract_instance = cls.get_instance(ledger_api, contract_address) + data = contract_instance.encodeABI("stake", args=[service_id]) + return dict(data=bytes.fromhex(data[2:])) + + @classmethod + def build_checkpoint_tx( + cls, + ledger_api: LedgerApi, + contract_address: str, + ) -> JSONLike: + """Build checkpoint tx.""" + contract_instance = cls.get_instance(ledger_api, contract_address) + data = contract_instance.encodeABI("checkpoint") + return dict(data=bytes.fromhex(data[2:])) + + @classmethod + def build_unstake_tx( + cls, + ledger_api: LedgerApi, + contract_address: str, + service_id: int, + ) -> JSONLike: + """Build unstake tx.""" + contract_instance = cls.get_instance(ledger_api, contract_address) + data = contract_instance.encodeABI("unstake", args=[service_id]) + return dict(data=bytes.fromhex(data[2:])) + + @classmethod + def available_rewards( + cls, + ledger_api: LedgerApi, + contract_address: str, + ) -> JSONLike: + """Get the available rewards.""" + contract_instance = cls.get_instance(ledger_api, contract_address) + res = contract_instance.functions.availableRewards().call() + return dict(data=res) + + @classmethod + def get_staking_rewards( + cls, + ledger_api: LedgerApi, + contract_address: str, + service_id: int, + ) -> JSONLike: + """Get the service's staking rewards.""" + contract = cls.get_instance(ledger_api, contract_address) + reward = contract.functions.calculateStakingReward(service_id).call() + return dict(data=reward) + + @classmethod + def get_next_checkpoint_ts( + cls, + ledger_api: LedgerApi, + contract_address: str, + ) -> JSONLike: + """Get the next checkpoint's timestamp.""" + contract = cls.get_instance(ledger_api, contract_address) + ts = contract.functions.getNextRewardCheckpointTimestamp().call() + return dict(data=ts) + + @classmethod + def ts_checkpoint( + cls, + ledger_api: LedgerApi, + contract_address: str, + ) -> JSONLike: + """Retrieve the checkpoint's timestamp.""" + contract = cls.get_instance(ledger_api, contract_address) + ts_checkpoint = contract.functions.tsCheckpoint().call() + return dict(data=ts_checkpoint) + + @classmethod + def liveness_ratio( + cls, + ledger_api: LedgerApi, + contract_address: str, + ) -> JSONLike: + """Retrieve the liveness ratio.""" + contract = cls.get_instance(ledger_api, contract_address) + liveness_ratio = contract.functions.livenessRatio().call() + return dict(data=liveness_ratio) + + @classmethod + def get_liveness_period( + cls, + ledger_api: LedgerApi, + contract_address: str, + ) -> JSONLike: + """Retrieve the liveness period.""" + contract = cls.get_instance(ledger_api, contract_address) + liveness_period = contract.functions.livenessPeriod().call() + return dict(data=liveness_period) + + @classmethod + def get_service_info( + cls, + ledger_api: LedgerApi, + contract_address: str, + service_id: int, + ) -> JSONLike: + """Retrieve the service info for a service.""" + contract = cls.get_instance(ledger_api, contract_address) + info = contract.functions.getServiceInfo(service_id).call() + return dict(data=info) + + @classmethod + def max_num_services( + cls, + ledger_api: LedgerApi, + contract_address: str, + ) -> JSONLike: + """Retrieve the max number of services.""" + contract = cls.get_instance(ledger_api, contract_address) + max_num_services = contract.functions.maxNumServices().call() + return dict(data=max_num_services) + + @classmethod + def get_service_ids( + cls, + ledger_api: LedgerApi, + contract_address: str, + ) -> JSONLike: + """Retrieve the service IDs.""" + contract = cls.get_instance(ledger_api, contract_address) + service_ids = contract.functions.getServiceIds().call() + return dict(data=service_ids) + + @classmethod + def get_min_staking_duration( + cls, + ledger_api: LedgerApi, + contract_address: str, + ) -> JSONLike: + """Retrieve the service IDs.""" + contract = cls.get_instance(ledger_api, contract_address) + duration = contract.functions.minStakingDuration().call() + return dict(data=duration) diff --git a/operate/data/contracts/staking_token/contract.yaml b/operate/data/contracts/staking_token/contract.yaml new file mode 100644 index 000000000..2fce9ed86 --- /dev/null +++ b/operate/data/contracts/staking_token/contract.yaml @@ -0,0 +1,23 @@ +name: staking_token +author: valory +version: 0.1.0 +type: contract +description: Service staking token contract +license: Apache-2.0 +aea_version: '>=1.0.0, <2.0.0' +fingerprint: + __init__.py: bafybeicmgkagyhgwn2ktcdjbprijalbdyj26cvza4d3b7uvmehvy4mmr3i + build/StakingToken.json: bafybeid5vwardpaeeggfbp4o2ea7wdhywaeamhvyolxmhv6v2ynil4st6q + contract.py: bafybeigzb6oxpyi7eiohftxuha5t3tcvj2bekihc77ts3dwzqpfl34ev6y +fingerprint_ignore_patterns: [] +contracts: [] +class_name: StakingTokenContract +contract_interface_paths: + ethereum: build/StakingToken.json +dependencies: + open-aea-ledger-ethereum: + version: ==1.52.0 + open-aea-test-autonomy: + version: ==0.14.12 + web3: + version: <7,>=6.0.0 diff --git a/operate/ledger/profiles.py b/operate/ledger/profiles.py index 94a15512f..0c668a445 100644 --- a/operate/ledger/profiles.py +++ b/operate/ledger/profiles.py @@ -36,7 +36,22 @@ } STAKING = { - ChainType.GNOSIS: "0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A", + ChainType.GNOSIS: { + "pearl_alpha": "0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A", + "pearl_beta": "0xef44fb0842ddef59d37f85d61a1ef492bba6135d" + } + + # ChainType.GNOSIS: { + # "pearl_alpha": { + # "stakingTokenAddress": "0x9Ec97Be9FF55ff11606ce7c589956f7Bf3D0b241", + # "stakingTokenInstanceAddress": "0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A" + # }, + # "pearl_beta": { + # "stakingTokenAddress": "0xEa00be6690a871827fAfD705440D20dd75e67AB1", + # "stakingTokenInstanceAddress": "0xef44fb0842ddef59d37f85d61a1ef492bba6135d" + # } + # } + } OLAS = { diff --git a/operate/services/manage.py b/operate/services/manage.py index 92aeec51b..d93e86687 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -21,6 +21,7 @@ import asyncio import logging +import os import shutil import traceback import typing as t @@ -48,7 +49,10 @@ OnChainUserParams, Service, ) -from operate.types import ServiceTemplate +from operate.types import ( + ServiceTemplate, + LedgerConfig +) from operate.wallet.master import MasterWalletManager @@ -121,12 +125,12 @@ def get_on_chain_manager(self, service: Service) -> OnChainManager: contracts=CONTRACTS[service.ledger_config.chain], ) - def get_eth_safe_tx_builder(self, service: Service) -> EthSafeTxBuilder: + def get_eth_safe_tx_builder(self, ledger_config: LedgerConfig) -> EthSafeTxBuilder: """Get EthSafeTxBuilder instance.""" return EthSafeTxBuilder( - rpc=service.ledger_config.rpc, - wallet=self.wallet_manager.load(service.ledger_config.type), - contracts=CONTRACTS[service.ledger_config.chain], + rpc=ledger_config.rpc, + wallet=self.wallet_manager.load(ledger_config.type), + contracts=CONTRACTS[ledger_config.chain], ) def load_or_create( @@ -168,26 +172,32 @@ def load_or_create( return service - def _get_on_chain_state(self, service: Service) -> OnChainState: - if service.chain_data.token == NON_EXISTENT_TOKEN: + def _get_on_chain_state(self, chain_config: ChainConfig) -> OnChainState: + chain_data = chain_config.chain_data + ledger_config = chain_config.ledger_config + if chain_data.token == NON_EXISTENT_TOKEN: service_state = OnChainState.NON_EXISTENT - service.chain_data.on_chain_state = service_state - service.store() + chain_data.on_chain_state = service_state + # TODO save service state + # service.store() return service_state - sftxb = self.get_eth_safe_tx_builder(service=service) - info = sftxb.info(token_id=service.chain_data.token) + sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) + info = sftxb.info(token_id=chain_data.token) service_state = OnChainState(info["service_state"]) - service.chain_data.on_chain_state = service_state - service.store() + chain_data.on_chain_state = service_state + # TODO save service state + # service.store() return service_state - def _get_on_chain_hash(self, service: Service) -> t.Optional[str]: - if service.chain_data.token == NON_EXISTENT_TOKEN: + def _get_on_chain_hash(self, chain_config: ChainConfig) -> t.Optional[str]: + chain_data = chain_config.chain_data + ledger_config = chain_config.ledger_config + if chain_data.token == NON_EXISTENT_TOKEN: return None - sftxb = self.get_eth_safe_tx_builder(service=service) - info = sftxb.info(token_id=service.chain_data.token) + sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) + info = sftxb.info(token_id=chain_data.token) config_hash = info["config_hash"] res = requests.get(f"{IPFS_GATEWAY}f01701220{config_hash}", timeout=30) if res.status_code == 200: @@ -385,7 +395,10 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to keys = service.keys instances = [key.address for key in keys] wallet = self.wallet_manager.load(ledger_config.type) - sftxb = self.get_eth_safe_tx_builder(service=service) + sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) + + # TODO fixme + os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc if user_params.use_staking and not sftxb.staking_slots_available( staking_contract=STAKING[ledger_config.chain] @@ -399,7 +412,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to chain_data.instances = info["instances"] chain_data.multisig = info["multisig"] service.store() - self.logger.info(f"Service state: {service.chain_data.on_chain_state.name}") + self.logger.info(f"Service state: {chain_data.on_chain_state.name}") if user_params.use_staking: self.logger.info("Checking staking compatibility") @@ -429,8 +442,8 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to f"address: {wallet.safe}; required olas: {required_olas}; your balance: {balance}" ) - on_chain_hash = self._get_on_chain_hash(service) - is_first_mint = self._get_on_chain_state(service) == OnChainState.NON_EXISTENT + on_chain_hash = self._get_on_chain_hash(chain_config=chain_config) + is_first_mint = self._get_on_chain_state(chain_config=chain_config) == OnChainState.NON_EXISTENT is_update = ( (not is_first_mint) and (on_chain_hash is not None) @@ -451,7 +464,13 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to # else: # self.logger.info("Updating the on-chain service") - if self._get_on_chain_state(service) == OnChainState.NON_EXISTENT: + if is_update: + self.terminate_service_on_chain_from_safe( + hash=hash, + chain_id=chain_id + ) + + if self._get_on_chain_state(chain_config=chain_config) == OnChainState.NON_EXISTENT: receipt = ( sftxb.new_tx() .add( @@ -489,9 +508,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to chain_data.on_chain_state = OnChainState.PRE_REGISTRATION service.store() - - print("!!!!!!!!!!!!!!!!!!!!!") - if self._get_on_chain_state(service) == OnChainState.PRE_REGISTRATION: + if self._get_on_chain_state(chain_config=chain_config) == OnChainState.PRE_REGISTRATION: cost_of_bond = user_params.cost_of_bond if user_params.use_staking: token_utility = "0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8" # nosec @@ -503,7 +520,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to registry_contracts.service_registry_token_utility.get_agent_bond( ledger_api=sftxb.ledger_api, contract_address=token_utility, - service_id=service.chain_data.token, + service_id=chain_data.token, agent_id=user_params.agent_id, ).get("bond") ) @@ -533,14 +550,14 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to self.logger.info("Activating service") sftxb.new_tx().add( sftxb.get_activate_data( - service_id=service.chain_data.token, + service_id=chain_data.token, cost_of_bond=cost_of_bond, ) ).settle() - service.chain_data.on_chain_state = OnChainState.ACTIVE_REGISTRATION + chain_data.on_chain_state = OnChainState.ACTIVE_REGISTRATION service.store() - if self._get_on_chain_state(service) == OnChainState.ACTIVE_REGISTRATION: + if self._get_on_chain_state(chain_config=chain_config) == OnChainState.ACTIVE_REGISTRATION: cost_of_bond = user_params.cost_of_bond if user_params.use_staking: token_utility = "0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8" # nosec @@ -580,40 +597,36 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to cost_of_bond = 1 self.logger.info( - f"Registering service: {service.chain_data.token} -> {instances}" + f"Registering service: {chain_data.token} -> {instances}" ) sftxb.new_tx().add( sftxb.get_register_instances_data( - service_id=service.chain_data.token, + service_id=chain_data.token, instances=instances, agents=[user_params.agent_id for _ in instances], cost_of_bond=cost_of_bond, ) ).settle() - service.chain_data.on_chain_state = OnChainState.FINISHED_REGISTRATION + chain_data.on_chain_state = OnChainState.FINISHED_REGISTRATION service.store() - if self._get_on_chain_state(service) == OnChainState.FINISHED_REGISTRATION: + if self._get_on_chain_state(chain_config=chain_config) == OnChainState.FINISHED_REGISTRATION: self.logger.info("Deploying service") sftxb.new_tx().add( sftxb.get_deploy_data( - service_id=service.chain_data.token, + service_id=chain_data.token, reuse_multisig=is_update, ) ).settle() - service.chain_data.on_chain_state = OnChainState.DEPLOYED + chain_data.on_chain_state = OnChainState.DEPLOYED service.store() # Update local Service - info = sftxb.info(token_id=service.chain_data.token) - service.chain_data = OnChainData( - token=service.chain_data.token, - instances=info["instances"], - multisig=info["multisig"], - staked=False, - on_chain_state=OnChainState(info["service_state"]), - user_params=service.chain_data.user_params, - ) + info = sftxb.info(token_id=chain_data.token) + chain_data.instances = info["instances"] + chain_data.multisig = info["multisig"] + chain_data.staked = False + chain_data.on_chain_state = OnChainState(info["service_state"]) service.store() def terminate_service_on_chain(self, hash: str) -> None: @@ -643,21 +656,48 @@ def terminate_service_on_chain(self, hash: str) -> None: service.chain_data.on_chain_state = OnChainState.TERMINATED_BONDED service.store() - def terminate_service_on_chain_from_safe(self, hash: str) -> None: + def terminate_service_on_chain_from_safe(self, hash: str, chain_id: int) -> None: """ Terminate service on-chain :param hash: Service hash """ - + self.logger.info("terminate_service_on_chain_from_safe") service = self.load_or_create(hash=hash) - sftxb = self.get_eth_safe_tx_builder(service=service) - info = sftxb.info(token_id=service.chain_data.token) - service.chain_data.on_chain_state = OnChainState(info["service_state"]) + chain_config = service.chain_configs[chain_id] + ledger_config = chain_config.ledger_config + chain_data = chain_config.chain_data + user_params = chain_config.chain_data.user_params + keys = service.keys + instances = [key.address for key in keys] + wallet = self.wallet_manager.load(ledger_config.type) + + # TODO fixme + os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc + + sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) + info = sftxb.info(token_id=chain_data.token) + chain_data.on_chain_state = OnChainState(info["service_state"]) + + + from icecream import ic + ic(info) + + + for staking_program in STAKING[ledger_config.chain]: + state = sftxb.staking_status( + service_id=chain_data.token, + staking_contract=STAKING[ledger_config.chain][staking_program], + ) + + print(state) + + import sys + sys.exit(1) if ( - service.chain_data.user_params.use_staking - and not self._can_unstake_service(hash=hash) + chain_data.user_params.use_staking + and not self._can_unstake_service_from_safe(hash=hash) ): return diff --git a/operate/services/protocol.py b/operate/services/protocol.py index b79522533..ea7bcda35 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -63,6 +63,9 @@ from operate.data.contracts.service_staking_token.contract import ( ServiceStakingTokenContract, ) +from operate.data.contracts.staking_token.contract import ( + StakingTokenContract, +) from operate.types import ContractAddresses from operate.utils.gnosis import ( MultiSendOperation, @@ -200,17 +203,48 @@ def __init__( directory=str(DATA_DIR / "contracts" / "service_staking_token") ), ) + self.staking_token_ctr = t.cast( + StakingTokenContract, + StakingTokenContract.from_dir( + directory=str(DATA_DIR / "contracts" / "staking_token") + ), + ) def status(self, service_id: int, staking_contract: str) -> StakingState: """Is the service staked?""" - return StakingState( - self.staking_ctr.get_instance( - ledger_api=self.ledger_api, - contract_address=staking_contract, + staking_state = None + + print(staking_contract) + try: + print("a") + staking_state = StakingState( + self.staking_ctr.get_instance( + ledger_api=self.ledger_api, + contract_address=staking_contract, + ) + .functions.getStakingState(service_id) + .call() ) - .functions.getStakingState(service_id) - .call() - ) + print("b") + return staking_state + except Exception: + print("c") + + try: + staking_state = StakingState( + self.staking_token_ctr.get_instance( + ledger_api=self.ledger_api, + contract_address=staking_contract, + ) + .functions.getStakingState(service_id) + .call() + ) + return staking_state + except Exception: + print("EXCEPTION") + print("d") + + return staking_state def slots_available(self, staking_contract: str) -> bool: """Check if there are available slots on the staking contract""" @@ -484,6 +518,14 @@ def ledger_api(self) -> LedgerApi: ) return ledger_api + def owner_of(self, token_id: int) -> str: + """Get owner of a service.""" + self._patch() + ledger_api, _ = OnChainHelper.get_ledger_and_crypto_objects( + chain_type=self.chain_type + ) + + def info(self, token_id: int) -> t.Dict: """Get service info.""" self._patch() @@ -498,7 +540,7 @@ def info(self, token_id: int) -> t.Dict: max_agents, number_of_agent_instances, service_state, - cannonical_agents, + canonical_agents, ) = get_service_info( ledger_api=ledger_api, chain_type=self.chain_type, @@ -517,7 +559,7 @@ def info(self, token_id: int) -> t.Dict: max_agents=max_agents, number_of_agent_instances=number_of_agent_instances, service_state=service_state, - cannonical_agents=cannonical_agents, + canonical_agents=canonical_agents, instances=instances, ) diff --git a/operate/services/service.py b/operate/services/service.py index 3c36e4050..e2d00dbdb 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -251,7 +251,7 @@ def ledger_configs(self) -> "LedgerConfigs": (_, config), *_ = override["config"]["ledger_apis"].items() # TODO chain name is inferred from the chain_id. The actual id provided on service.yaml is ignored. chain = ChainType.from_id(cid=config["chain_id"]) - ledger_configs[config["chain_id"]] = LedgerConfig( + ledger_configs[str(config["chain_id"])] = LedgerConfig( rpc=config["address"], chain=chain, type=LedgerType.ETHEREUM, diff --git a/operate/types.py b/operate/types.py index a622d57c0..0455cedc0 100644 --- a/operate/types.py +++ b/operate/types.py @@ -193,7 +193,7 @@ class ConfigurationTemplate(TypedDict): fund_requirements: FundRequirementsTemplate -ConfigurationTemplates = t.Dict[int, ConfigurationTemplate] +ConfigurationTemplates = t.Dict[str, ConfigurationTemplate] class ServiceTemplate(TypedDict): @@ -204,7 +204,7 @@ class ServiceTemplate(TypedDict): image: str description: str service_version: str - home_chain_id: int + home_chain_id: str configurations: ConfigurationTemplates From f78a34358001cb7d40841f588a34d65617bb12ea Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 13 Aug 2024 13:19:49 +0200 Subject: [PATCH 10/99] chore: update --- .../data/contracts/staking_token/__init__.py | 20 -- .../data/contracts/staking_token/contract.py | 192 ------------------ .../contracts/staking_token/contract.yaml | 23 --- operate/services/manage.py | 14 +- operate/services/protocol.py | 54 ++--- 5 files changed, 26 insertions(+), 277 deletions(-) delete mode 100644 operate/data/contracts/staking_token/__init__.py delete mode 100644 operate/data/contracts/staking_token/contract.py delete mode 100644 operate/data/contracts/staking_token/contract.yaml diff --git a/operate/data/contracts/staking_token/__init__.py b/operate/data/contracts/staking_token/__init__.py deleted file mode 100644 index 4682f8155..000000000 --- a/operate/data/contracts/staking_token/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2024 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This module contains the support resources for the staking contract.""" diff --git a/operate/data/contracts/staking_token/contract.py b/operate/data/contracts/staking_token/contract.py deleted file mode 100644 index 384beea7a..000000000 --- a/operate/data/contracts/staking_token/contract.py +++ /dev/null @@ -1,192 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2023-2024 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""This module contains the class to connect to the `ServiceStakingTokenMechUsage` contract.""" - -from enum import Enum - -from aea.common import JSONLike -from aea.configurations.base import PublicId -from aea.contracts.base import Contract -from aea.crypto.base import LedgerApi - - -class StakingTokenContract(Contract): - """The Service Staking contract.""" - - contract_id = PublicId.from_str("valory/staking_token:0.1.0") - - @classmethod - def get_service_staking_state( - cls, - ledger_api: LedgerApi, - contract_address: str, - service_id: int, - ) -> JSONLike: - """Check whether the service is staked.""" - contract_instance = cls.get_instance(ledger_api, contract_address) - res = contract_instance.functions.getStakingState(service_id).call() - return dict(data=res) - - @classmethod - def build_stake_tx( - cls, - ledger_api: LedgerApi, - contract_address: str, - service_id: int, - ) -> JSONLike: - """Build stake tx.""" - contract_instance = cls.get_instance(ledger_api, contract_address) - data = contract_instance.encodeABI("stake", args=[service_id]) - return dict(data=bytes.fromhex(data[2:])) - - @classmethod - def build_checkpoint_tx( - cls, - ledger_api: LedgerApi, - contract_address: str, - ) -> JSONLike: - """Build checkpoint tx.""" - contract_instance = cls.get_instance(ledger_api, contract_address) - data = contract_instance.encodeABI("checkpoint") - return dict(data=bytes.fromhex(data[2:])) - - @classmethod - def build_unstake_tx( - cls, - ledger_api: LedgerApi, - contract_address: str, - service_id: int, - ) -> JSONLike: - """Build unstake tx.""" - contract_instance = cls.get_instance(ledger_api, contract_address) - data = contract_instance.encodeABI("unstake", args=[service_id]) - return dict(data=bytes.fromhex(data[2:])) - - @classmethod - def available_rewards( - cls, - ledger_api: LedgerApi, - contract_address: str, - ) -> JSONLike: - """Get the available rewards.""" - contract_instance = cls.get_instance(ledger_api, contract_address) - res = contract_instance.functions.availableRewards().call() - return dict(data=res) - - @classmethod - def get_staking_rewards( - cls, - ledger_api: LedgerApi, - contract_address: str, - service_id: int, - ) -> JSONLike: - """Get the service's staking rewards.""" - contract = cls.get_instance(ledger_api, contract_address) - reward = contract.functions.calculateStakingReward(service_id).call() - return dict(data=reward) - - @classmethod - def get_next_checkpoint_ts( - cls, - ledger_api: LedgerApi, - contract_address: str, - ) -> JSONLike: - """Get the next checkpoint's timestamp.""" - contract = cls.get_instance(ledger_api, contract_address) - ts = contract.functions.getNextRewardCheckpointTimestamp().call() - return dict(data=ts) - - @classmethod - def ts_checkpoint( - cls, - ledger_api: LedgerApi, - contract_address: str, - ) -> JSONLike: - """Retrieve the checkpoint's timestamp.""" - contract = cls.get_instance(ledger_api, contract_address) - ts_checkpoint = contract.functions.tsCheckpoint().call() - return dict(data=ts_checkpoint) - - @classmethod - def liveness_ratio( - cls, - ledger_api: LedgerApi, - contract_address: str, - ) -> JSONLike: - """Retrieve the liveness ratio.""" - contract = cls.get_instance(ledger_api, contract_address) - liveness_ratio = contract.functions.livenessRatio().call() - return dict(data=liveness_ratio) - - @classmethod - def get_liveness_period( - cls, - ledger_api: LedgerApi, - contract_address: str, - ) -> JSONLike: - """Retrieve the liveness period.""" - contract = cls.get_instance(ledger_api, contract_address) - liveness_period = contract.functions.livenessPeriod().call() - return dict(data=liveness_period) - - @classmethod - def get_service_info( - cls, - ledger_api: LedgerApi, - contract_address: str, - service_id: int, - ) -> JSONLike: - """Retrieve the service info for a service.""" - contract = cls.get_instance(ledger_api, contract_address) - info = contract.functions.getServiceInfo(service_id).call() - return dict(data=info) - - @classmethod - def max_num_services( - cls, - ledger_api: LedgerApi, - contract_address: str, - ) -> JSONLike: - """Retrieve the max number of services.""" - contract = cls.get_instance(ledger_api, contract_address) - max_num_services = contract.functions.maxNumServices().call() - return dict(data=max_num_services) - - @classmethod - def get_service_ids( - cls, - ledger_api: LedgerApi, - contract_address: str, - ) -> JSONLike: - """Retrieve the service IDs.""" - contract = cls.get_instance(ledger_api, contract_address) - service_ids = contract.functions.getServiceIds().call() - return dict(data=service_ids) - - @classmethod - def get_min_staking_duration( - cls, - ledger_api: LedgerApi, - contract_address: str, - ) -> JSONLike: - """Retrieve the service IDs.""" - contract = cls.get_instance(ledger_api, contract_address) - duration = contract.functions.minStakingDuration().call() - return dict(data=duration) diff --git a/operate/data/contracts/staking_token/contract.yaml b/operate/data/contracts/staking_token/contract.yaml deleted file mode 100644 index 2fce9ed86..000000000 --- a/operate/data/contracts/staking_token/contract.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: staking_token -author: valory -version: 0.1.0 -type: contract -description: Service staking token contract -license: Apache-2.0 -aea_version: '>=1.0.0, <2.0.0' -fingerprint: - __init__.py: bafybeicmgkagyhgwn2ktcdjbprijalbdyj26cvza4d3b7uvmehvy4mmr3i - build/StakingToken.json: bafybeid5vwardpaeeggfbp4o2ea7wdhywaeamhvyolxmhv6v2ynil4st6q - contract.py: bafybeigzb6oxpyi7eiohftxuha5t3tcvj2bekihc77ts3dwzqpfl34ev6y -fingerprint_ignore_patterns: [] -contracts: [] -class_name: StakingTokenContract -contract_interface_paths: - ethereum: build/StakingToken.json -dependencies: - open-aea-ledger-ethereum: - version: ==1.52.0 - open-aea-test-autonomy: - version: ==0.14.12 - web3: - version: <7,>=6.0.0 diff --git a/operate/services/manage.py b/operate/services/manage.py index d93e86687..abe7893b7 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -684,17 +684,29 @@ def terminate_service_on_chain_from_safe(self, hash: str, chain_id: int) -> None ic(info) + # Determine if the service is staked in a known staking program + current_staking_program = None for staking_program in STAKING[ledger_config.chain]: state = sftxb.staking_status( service_id=chain_data.token, staking_contract=STAKING[ledger_config.chain][staking_program], ) + if state in (StakingState.STAKED, StakingState.EVICTED): + current_staking_program = staking_program - print(state) + is_staked = current_staking_program is not None + # if is_staked: + # can_unstake = and not self._can_unstake_service_from_safe(hash=hash) + print(current_staking_program) + print(is_staked) import sys sys.exit(1) + + + + if ( chain_data.user_params.use_staking and not self._can_unstake_service_from_safe(hash=hash) diff --git a/operate/services/protocol.py b/operate/services/protocol.py index ea7bcda35..78e1d4e4e 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -63,9 +63,6 @@ from operate.data.contracts.service_staking_token.contract import ( ServiceStakingTokenContract, ) -from operate.data.contracts.staking_token.contract import ( - StakingTokenContract, -) from operate.types import ContractAddresses from operate.utils.gnosis import ( MultiSendOperation, @@ -203,48 +200,23 @@ def __init__( directory=str(DATA_DIR / "contracts" / "service_staking_token") ), ) - self.staking_token_ctr = t.cast( - StakingTokenContract, - StakingTokenContract.from_dir( - directory=str(DATA_DIR / "contracts" / "staking_token") - ), - ) + # self.staking_token_ctr = t.cast( + # StakingTokenContract, + # StakingTokenContract.from_dir( + # directory=str(DATA_DIR / "contracts" / "staking_token") + # ), + # ) def status(self, service_id: int, staking_contract: str) -> StakingState: """Is the service staked?""" - staking_state = None - - print(staking_contract) - try: - print("a") - staking_state = StakingState( - self.staking_ctr.get_instance( - ledger_api=self.ledger_api, - contract_address=staking_contract, - ) - .functions.getStakingState(service_id) - .call() + return StakingState( + self.staking_ctr.get_instance( + ledger_api=self.ledger_api, + contract_address=staking_contract, ) - print("b") - return staking_state - except Exception: - print("c") - - try: - staking_state = StakingState( - self.staking_token_ctr.get_instance( - ledger_api=self.ledger_api, - contract_address=staking_contract, - ) - .functions.getStakingState(service_id) - .call() - ) - return staking_state - except Exception: - print("EXCEPTION") - print("d") - - return staking_state + .functions.getStakingState(service_id) + .call() + ) def slots_available(self, staking_contract: str) -> bool: """Check if there are available slots on the staking contract""" From 11b8dacf284c24db56c0f43beab0eb3584da8fd7 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 13 Aug 2024 13:41:44 +0200 Subject: [PATCH 11/99] chore: can unstake method --- operate/services/protocol.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/operate/services/protocol.py b/operate/services/protocol.py index 78e1d4e4e..7c6c6cba0 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -1174,6 +1174,21 @@ def staking_status(self, service_id: int, staking_contract: str) -> StakingState staking_contract=staking_contract, ) + def can_unstake(self, service_id: int, staking_contract: str) -> bool: + """Can unstake the service?""" + try: + StakingManager( + key=self.wallet.key_path, + password=self.wallet.password, + chain_type=self.chain_type, + ).check_if_unstaking_possible( + service_id=service_id, + staking_contract=staking_contract, + ) + return True + except ValueError: + return False + def get_swap_data(self, service_id: int, multisig: str, owner_key: str) -> t.Dict: """Swap safe owner.""" # TODO: Discuss implementation From 410bea2bd02ff54da69387fe8f3b58793e09f7b0 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 14 Aug 2024 00:33:36 +0200 Subject: [PATCH 12/99] chore: updates --- operate/services/manage.py | 221 ++++++++++++++++++++++------------- operate/services/protocol.py | 151 +++++++++++++++++++++--- operate/types.py | 10 +- 3 files changed, 274 insertions(+), 108 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index abe7893b7..a8531a45b 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -25,6 +25,7 @@ import shutil import traceback import typing as t +from collections import Counter from concurrent.futures import ThreadPoolExecutor from pathlib import Path @@ -69,6 +70,8 @@ DOCKER_COMPOSE_YAML = "docker-compose.yaml" SERVICE_YAML = "service.yaml" HTTP_OK = 200 +URI_HASH_POSITION = 7 +IPFS_GATEWAY = "https://gateway.autonolas.tech/ipfs/" class ServiceManager: @@ -363,30 +366,26 @@ def deploy_service_onchain( # pylint: disable=too-many-statements def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too-many-locals self, hash: str, - update: bool = False, ) -> None: service = self.load_or_create(hash=hash) for chain_id in service.chain_configs.keys(): self._deploy_service_onchain_from_safe( hash=hash, - update=update, chain_id=chain_id, ) def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too-many-locals self, hash: str, - update: bool, - chain_id: int, + chain_id: str, ) -> None: """ Deploy as service on-chain :param hash: Service hash """ - self.logger.info("DEPLOY SERVICE ONCHAIN FROM SAFE ====================") - self.logger.info("Loading service") + self.logger.info(f"_deploy_service_onchain_from_safe {chain_id=}") service = self.load_or_create(hash=hash) chain_config = service.chain_configs[chain_id] ledger_config = chain_config.ledger_config @@ -397,13 +396,9 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to wallet = self.wallet_manager.load(ledger_config.type) sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) - # TODO fixme + # TODO fix this os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc - - if user_params.use_staking and not sftxb.staking_slots_available( - staking_contract=STAKING[ledger_config.chain] - ): - raise ValueError("No staking slots available") + os.environ["OPEN_AUTONOMY_SUBGRAPH_URL"] = "https://subgraph.autonolas.tech/subgraphs/name/autonolas-staging" if chain_data.token > -1: self.logger.info("Syncing service state") @@ -411,9 +406,24 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to chain_data.on_chain_state = OnChainState(info["service_state"]) chain_data.instances = info["instances"] chain_data.multisig = info["multisig"] + current_agent_id = info["canonical_agents"][0] # TODO Allow multiple agents service.store() self.logger.info(f"Service state: {chain_data.on_chain_state.name}") + if user_params.use_staking: + staking_params = sftxb.get_staking_params( + staking_contract=STAKING[ledger_config.chain][user_params.staking_program_id], + ) + else: # TODO fix this - using pearl beta params + staking_params = dict( + agent_ids=[25], + service_registry="0x9338b5153AE39BB89f50468E608eD9d764B755fD", # nosec + staking_token="0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f", # nosec + service_registry_token_utility="0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8", # nosec + min_staking_deposit=20000000000000000000, + activity_checker="0x155547857680A6D51bebC5603397488988DEb1c8" # nosec + ) + if user_params.use_staking: self.logger.info("Checking staking compatibility") if chain_data.on_chain_state in ( @@ -421,10 +431,10 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to OnChainState.PRE_REGISTRATION, ): required_olas = ( - user_params.olas_cost_of_bond + user_params.olas_required_to_stake + staking_params["min_staking_deposit"] + staking_params["min_staking_deposit"] # bond = staking ) elif chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: - required_olas = user_params.olas_required_to_stake + required_olas = staking_params["min_staking_deposit"] else: required_olas = 0 @@ -447,47 +457,85 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to is_update = ( (not is_first_mint) and (on_chain_hash is not None) - and (on_chain_hash != service.hash) + and (on_chain_hash != service.hash or current_agent_id != staking_params["agent_ids"][0]) ) self.logger.info(f"{on_chain_hash=}") + self.logger.info(f"{service.hash=}") self.logger.info(f"{is_first_mint=}") self.logger.info(f"{is_update=}") - is_update = update # TODO fix - # if is_update: - # self.terminate_service_on_chain_from_safe(hash=hash) - - # if is_first_mint or (is_update and self._get_on_chain_state(service) == OnChainState.PRE_REGISTRATION): - # if not is_update: - # self.logger.info("Minting the on-chain service") - # else: - # self.logger.info("Updating the on-chain service") - if is_update: - self.terminate_service_on_chain_from_safe( + self._terminate_service_on_chain_from_safe( hash=hash, chain_id=chain_id ) + # Update service + if self._get_on_chain_state(chain_config=chain_config) == OnChainState.PRE_REGISTRATION: + self.logger.info("Updating service") + receipt = ( + sftxb.new_tx() + .add( + sftxb.get_mint_tx_data( + package_path=service.service_path, + agent_id=staking_params["agent_ids"][0], + number_of_slots=service.helper.config.number_of_agents, + cost_of_bond=( + staking_params["min_staking_deposit"] + if user_params.use_staking + else user_params.cost_of_bond + ), + threshold=user_params.threshold, + nft=IPFSHash(user_params.nft), + update_token=chain_data.token, + token=( + staking_params["staking_token"] + if user_params.use_staking + else None + ), + ) + ) + .settle() + ) + event_data, *_ = t.cast( + t.Tuple, + registry_contracts.service_registry.process_receipt( + ledger_api=sftxb.ledger_api, + contract_address=staking_params["service_registry"], + event="UpdateService", + receipt=receipt, + ).get("events"), + ) + chain_data.on_chain_state = OnChainState.PRE_REGISTRATION + service.store() + + # Mint service if self._get_on_chain_state(chain_config=chain_config) == OnChainState.NON_EXISTENT: + + if user_params.use_staking and not sftxb.staking_slots_available( + staking_contract=STAKING[ledger_config.chain][user_params.staking_program_id] + ): + raise ValueError("No staking slots available") + + self.logger.info("Minting service") receipt = ( sftxb.new_tx() .add( sftxb.get_mint_tx_data( package_path=service.service_path, - agent_id=user_params.agent_id, + agent_id=staking_params["agent_ids"][0], number_of_slots=service.helper.config.number_of_agents, cost_of_bond=( - user_params.olas_cost_of_bond + staking_params["min_staking_deposit"] if user_params.use_staking else user_params.cost_of_bond ), threshold=user_params.threshold, nft=IPFSHash(user_params.nft), - update_token=chain_data.token if update else None, + update_token=None, token=( - OLAS[ledger_config.chain] + staking_params["staking_token"] if user_params.use_staking else None ), @@ -499,7 +547,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to t.Tuple, registry_contracts.service_registry.process_receipt( ledger_api=sftxb.ledger_api, - contract_address="0x9338b5153AE39BB89f50468E608eD9d764B755fD", + contract_address=staking_params["service_registry"], event="CreateService", receipt=receipt, ).get("events"), @@ -509,10 +557,11 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to service.store() if self._get_on_chain_state(chain_config=chain_config) == OnChainState.PRE_REGISTRATION: - cost_of_bond = user_params.cost_of_bond + cost_of_bond = staking_params["min_staking_deposit"] if user_params.use_staking: - token_utility = "0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8" # nosec - olas_token = "0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f" # nosec + token_utility = staking_params["service_registry_token_utility"] + olas_token = staking_params["staking_token"] + agent_id = staking_params["agent_ids"][0] self.logger.info( f"Approving OLAS as bonding token from {wallet.safe} to {token_utility}" ) @@ -521,7 +570,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to ledger_api=sftxb.ledger_api, contract_address=token_utility, service_id=chain_data.token, - agent_id=user_params.agent_id, + agent_id=agent_id, ).get("bond") ) sftxb.new_tx().add( @@ -560,8 +609,9 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to if self._get_on_chain_state(chain_config=chain_config) == OnChainState.ACTIVE_REGISTRATION: cost_of_bond = user_params.cost_of_bond if user_params.use_staking: - token_utility = "0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8" # nosec - olas_token = "0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f" # nosec + token_utility = staking_params["service_registry_token_utility"] + olas_token = staking_params["staking_token"] + agent_id = staking_params["agent_ids"][0] self.logger.info( f"Approving OLAS as bonding token from {wallet.safe} to {token_utility}" ) @@ -569,8 +619,8 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to registry_contracts.service_registry_token_utility.get_agent_bond( ledger_api=sftxb.ledger_api, contract_address=token_utility, - service_id=service.chain_data.token, - agent_id=user_params.agent_id, + service_id=chain_data.token, + agent_id=agent_id, ).get("bond") ) sftxb.new_tx().add( @@ -603,7 +653,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to sftxb.get_register_instances_data( service_id=chain_data.token, instances=instances, - agents=[user_params.agent_id for _ in instances], + agents=[agent_id for _ in instances], cost_of_bond=cost_of_bond, ) ).settle() @@ -612,6 +662,9 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to if self._get_on_chain_state(chain_config=chain_config) == OnChainState.FINISHED_REGISTRATION: self.logger.info("Deploying service") + + current_safe_owners = sftxb.get_service_safe_owners(service_id=chain_data.token) + print(f"{current_safe_owners=}") sftxb.new_tx().add( sftxb.get_deploy_data( service_id=chain_data.token, @@ -656,7 +709,7 @@ def terminate_service_on_chain(self, hash: str) -> None: service.chain_data.on_chain_state = OnChainState.TERMINATED_BONDED service.store() - def terminate_service_on_chain_from_safe(self, hash: str, chain_id: int) -> None: + def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: """ Terminate service on-chain @@ -679,11 +732,6 @@ def terminate_service_on_chain_from_safe(self, hash: str, chain_id: int) -> None info = sftxb.info(token_id=chain_data.token) chain_data.on_chain_state = OnChainState(info["service_state"]) - - from icecream import ic - ic(info) - - # Determine if the service is staked in a known staking program current_staking_program = None for staking_program in STAKING[ledger_config.chain]: @@ -696,26 +744,23 @@ def terminate_service_on_chain_from_safe(self, hash: str, chain_id: int) -> None is_staked = current_staking_program is not None - # if is_staked: - # can_unstake = and not self._can_unstake_service_from_safe(hash=hash) - - print(current_staking_program) - print(is_staked) - import sys - sys.exit(1) - - - + can_unstake = False + if current_staking_program is not None: + can_unstake = sftxb.can_unstake( + service_id=chain_data.token, + staking_contract=STAKING[ledger_config.chain][current_staking_program], + ) - if ( - chain_data.user_params.use_staking - and not self._can_unstake_service_from_safe(hash=hash) - ): + # Cannot unstake, terminate flow. + if is_staked and not can_unstake: + self.logger.info("Service cannot be terminated on-chain: cannot unstake.") return - self.unstake_service_on_chain(hash=hash) + # Unstake the service if applies + if is_staked and can_unstake: + self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) - if self._get_on_chain_state(service) in ( + if self._get_on_chain_state(chain_config) in ( OnChainState.ACTIVE_REGISTRATION, OnChainState.FINISHED_REGISTRATION, OnChainState.DEPLOYED, @@ -723,26 +768,32 @@ def terminate_service_on_chain_from_safe(self, hash: str, chain_id: int) -> None self.logger.info("Terminating service") sftxb.new_tx().add( sftxb.get_terminate_data( - service_id=service.chain_data.token, + service_id=chain_data.token, ) ).settle() - if self._get_on_chain_state(service) == OnChainState.TERMINATED_BONDED: + if self._get_on_chain_state(chain_config) == OnChainState.TERMINATED_BONDED: self.logger.info("Unbonding service") sftxb.new_tx().add( sftxb.get_unbond_data( - service_id=service.chain_data.token, + service_id=chain_data.token, ) ).settle() - if [["$current_safe_owners" == "['$agent_address']"]]: - sftx = self.get_eth_safe_tx_builder(service=old_service) # noqa: E800 - sftx.swap( # noqa: E800 - service_id=old_service.chain_data.token, # noqa: E800 - multisig=old_service.chain_data.multisig, # noqa: E800 + # Swap service safe + current_safe_owners = sftxb.get_service_safe_owners(service_id=chain_data.token) + counter_current_safe_owners = Counter(s.lower() for s in current_safe_owners) + counter_instances = Counter(s.lower() for s in instances) + + if counter_current_safe_owners == counter_instances: + self.logger.info("Swapping Safe owners") + sftxb.swap( # noqa: E800 + service_id=chain_data.token, # noqa: E800 + multisig=chain_data.multisig, # TODO this can be read from the registry owner_key=str( - self.keys_manager.get(key=owner).private_key + self.keys_manager.get(key=current_safe_owners[0]).private_key # TODO allow multiple owners ), # noqa: E800 + new_owner_address=wallet.safe if wallet.safe else wallet.crypto.address # TODO it should always be safe address ) # noqa: E800 def unbond_service_on_chain(self, hash: str) -> None: @@ -907,39 +958,45 @@ def unstake_service_on_chain(self, hash: str) -> None: service.chain_data.staked = False service.store() - def unstake_service_on_chain_from_safe(self, hash: str) -> None: + def unstake_service_on_chain_from_safe(self, hash: str, chain_id: str, staking_program_id: str) -> None: """ Unbond service on-chain :param hash: Service hash """ + + self.logger.info("unstake_service_on_chain_from_safe") service = self.load_or_create(hash=hash) - if not service.chain_data.user_params.use_staking: + chain_config = service.chain_configs[chain_id] + ledger_config = chain_config.ledger_config + chain_data = chain_config.chain_data + + if not chain_data.user_params.use_staking: self.logger.info("Cannot unstake service, `use_staking` is set to false") return - sftxb = self.get_eth_safe_tx_builder(service=service) + sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) state = sftxb.staking_status( - service_id=service.chain_data.token, - staking_contract=STAKING[service.ledger_config.chain], + service_id=chain_data.token, + staking_contract=STAKING[ledger_config.chain][staking_program_id], ) self.logger.info( - f"Staking status for service {service.chain_data.token}: {state}" + f"Staking status for service {chain_data.token}: {state}" ) if state not in {StakingState.STAKED, StakingState.EVICTED}: self.logger.info("Cannot unstake service, it's not staked") - service.chain_data.staked = False + chain_data.staked = False service.store() return - self.logger.info(f"Unstaking service: {service.chain_data.token}") + self.logger.info(f"Unstaking service: {chain_data.token}") sftxb.new_tx().add( sftxb.get_unstaking_data( - service_id=service.chain_data.token, - staking_contract=STAKING[service.ledger_config.chain], + service_id=chain_data.token, + staking_contract=STAKING[ledger_config.chain][staking_program_id], ) ).settle() - service.chain_data.staked = False + chain_data.staked = False service.store() def fund_service( # pylint: disable=too-many-arguments diff --git a/operate/services/protocol.py b/operate/services/protocol.py index 7c6c6cba0..92d3f6ad2 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -67,6 +67,7 @@ from operate.utils.gnosis import ( MultiSendOperation, SafeOperation, + get_owners, hash_payload_to_hex, skill_input_hex_to_payload, ) @@ -200,12 +201,6 @@ def __init__( directory=str(DATA_DIR / "contracts" / "service_staking_token") ), ) - # self.staking_token_ctr = t.cast( - # StakingTokenContract, - # StakingTokenContract.from_dir( - # directory=str(DATA_DIR / "contracts" / "staking_token") - # ), - # ) def status(self, service_id: int, staking_contract: str) -> StakingState: """Is the service staked?""" @@ -245,6 +240,48 @@ def service_info(self, staking_contract: str, service_id: int) -> dict: staking_contract, service_id, ).get("data") + + def agent_ids(self, staking_contract: str) -> t.List[int]: + instance = self.staking_ctr.get_instance( + ledger_api=self.ledger_api, + contract_address=staking_contract, + ) + return instance.functions.getAgentIds().call() + + def service_registry(self, staking_contract: str) -> str: + instance = self.staking_ctr.get_instance( + ledger_api=self.ledger_api, + contract_address=staking_contract, + ) + return instance.functions.serviceRegistry().call() + + def staking_token(self, staking_contract: str) -> str: + instance = self.staking_ctr.get_instance( + ledger_api=self.ledger_api, + contract_address=staking_contract, + ) + return instance.functions.stakingToken().call() + + def service_registry_token_utility(self, staking_contract: str) -> str: + instance = self.staking_ctr.get_instance( + ledger_api=self.ledger_api, + contract_address=staking_contract, + ) + return instance.functions.serviceRegistryTokenUtility().call() + + def min_staking_deposit(self, staking_contract: str) -> str: + instance = self.staking_ctr.get_instance( + ledger_api=self.ledger_api, + contract_address=staking_contract, + ) + return instance.functions.minStakingDeposit().call() + + def activity_checker(self, staking_contract: str) -> str: + instance = self.staking_ctr.get_instance( + ledger_api=self.ledger_api, + contract_address=staking_contract, + ) + return instance.functions.activityChecker().call() def check_staking_compatibility( self, @@ -535,11 +572,38 @@ def info(self, token_id: int) -> t.Dict: instances=instances, ) + + def get_service_safe_owners(self, service_id: int) -> t.List[str]: + """Get list of owners.""" + ledger_api, _ = OnChainHelper.get_ledger_and_crypto_objects( + chain_type=self.chain_type + ) + ( + _, + multisig_address, + _, + _, + _, + _, + _, + _, + ) = get_service_info( + ledger_api=ledger_api, + chain_type=self.chain_type, + token_id=service_id, + ) + return registry_contracts.gnosis_safe.get_owners( + ledger_api=ledger_api, + contract_address=multisig_address, + ).get("owners", []) + + def swap( # pylint: disable=too-many-arguments,too-many-locals self, service_id: int, multisig: str, owner_key: str, + new_owner_address: str ) -> None: """Swap safe owner.""" logging.info(f"Swapping safe for service {service_id} [{multisig}]...") @@ -569,7 +633,7 @@ def swap( # pylint: disable=too-many-arguments,too-many-locals contract_address=multisig, old_owner=manager.ledger_api.api.to_checksum_address(owner_to_swap), new_owner=manager.ledger_api.api.to_checksum_address( - manager.crypto.address + new_owner_address ), ).get("data") multisend_txs.append( @@ -909,7 +973,7 @@ def get_mint_tx_data( # pylint: disable=too-many-arguments ) .load_metadata() .verify_nft(nft=nft) - .verify_service_dependencies(agent_id=agent_id) + #.verify_service_dependencies(agent_id=agent_id) # TODO add this check once subgraph production indexes agent 25 .publish_metadata() ) instance = registry_contracts.service_manager.get_instance( @@ -917,17 +981,30 @@ def get_mint_tx_data( # pylint: disable=too-many-arguments contract_address=self.contracts["service_manager"], ) - txd = instance.encodeABI( - fn_name="create" if update_token is None else "update", - args=[ - self.wallet.safe, - token or ETHEREUM_ERC20, - manager.metadata_hash, - [agent_id], - [[number_of_slots, cost_of_bond]], - threshold, - ], - ) + if update_token is None: + txd = instance.encodeABI( + fn_name="create", + args=[ + self.wallet.safe, + token or ETHEREUM_ERC20, + manager.metadata_hash, + [agent_id], + [[number_of_slots, cost_of_bond]], + threshold, + ], + ) + else: + txd = instance.encodeABI( + fn_name="update", + args=[ + token or ETHEREUM_ERC20, + manager.metadata_hash, + [agent_id], + [[number_of_slots, cost_of_bond]], + threshold, + update_token + ], + ) return { "to": self.contracts["service_manager"], @@ -1174,6 +1251,42 @@ def staking_status(self, service_id: int, staking_contract: str) -> StakingState staking_contract=staking_contract, ) + def get_staking_params(self, staking_contract: str) -> t.Dict: + """Get agent IDs for the staking contract""" + self._patch() + staking_manager = StakingManager( + key=self.wallet.key_path, + password=self.wallet.password, + chain_type=self.chain_type, + ) + agent_ids = staking_manager.agent_ids( + staking_contract=staking_contract, + ) + service_registry = staking_manager.service_registry( + staking_contract=staking_contract, + ) + staking_token = staking_manager.staking_token( + staking_contract=staking_contract, + ) + service_registry_token_utility = staking_manager.service_registry_token_utility( + staking_contract=staking_contract, + ) + min_staking_deposit = staking_manager.min_staking_deposit( + staking_contract=staking_contract, + ) + activity_checker = staking_manager.activity_checker( + staking_contract=staking_contract, + ) + + return dict( + agent_ids=agent_ids, + service_registry=service_registry, + staking_token=staking_token, + service_registry_token_utility=service_registry_token_utility, + min_staking_deposit=min_staking_deposit, + activity_checker=activity_checker + ) + def can_unstake(self, service_id: int, staking_contract: str) -> bool: """Can unstake the service?""" try: diff --git a/operate/types.py b/operate/types.py index 0455cedc0..7360db461 100644 --- a/operate/types.py +++ b/operate/types.py @@ -182,14 +182,12 @@ class FundRequirementsTemplate(TypedDict): class ConfigurationTemplate(TypedDict): """Configuration template.""" + staking_program_id: str nft: str rpc: str - agent_id: int threshold: int use_staking: bool cost_of_bond: int - olas_cost_of_bond: int - olas_required_to_stake: int fund_requirements: FundRequirementsTemplate @@ -228,13 +226,11 @@ class OnChainFundRequirements(LocalResource): class OnChainUserParams(LocalResource): """On-chain user params.""" + staking_program_id: str nft: str - agent_id: int threshold: int use_staking: bool cost_of_bond: int - olas_cost_of_bond: int - olas_required_to_stake: int fund_requirements: OnChainFundRequirements @classmethod @@ -268,4 +264,4 @@ def from_json(cls, obj: t.Dict) -> "ChainConfig": return super().from_json(obj) # type: ignore -ChainConfigs = t.Dict[int, ChainConfig] +ChainConfigs = t.Dict[str, ChainConfig] From 489df50d6e451764d34f49b7a582a87a120e67a3 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Wed, 14 Aug 2024 12:00:44 +0400 Subject: [PATCH 13/99] chore: update low gas alert logic --- frontend/components/Main/MainGasBalance.tsx | 14 ++++++------- .../Main/MainHeader/AgentButton/index.tsx | 6 +++--- frontend/components/Main/MainHeader/index.tsx | 7 +++---- frontend/components/Main/MainOlasBalance.tsx | 5 ++--- frontend/constants/thresholds.ts | 1 + frontend/context/BalanceProvider.tsx | 20 +++++++++++++++++++ 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/frontend/components/Main/MainGasBalance.tsx b/frontend/components/Main/MainGasBalance.tsx index 0d1f83f26..f3b14438d 100644 --- a/frontend/components/Main/MainGasBalance.tsx +++ b/frontend/components/Main/MainGasBalance.tsx @@ -4,7 +4,6 @@ import { useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; import { COLOR } from '@/constants/colors'; -import { LOW_BALANCE } from '@/constants/thresholds'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useStore } from '@/hooks/useStore'; @@ -34,7 +33,7 @@ const FineDot = styled(Dot)` `; const BalanceStatus = () => { - const { isBalanceLoaded, safeBalance } = useBalance(); + const { isBalanceLoaded, isLowBalance } = useBalance(); const { storeState } = useStore(); const { showNotification } = useElectronApi(); @@ -44,35 +43,34 @@ const BalanceStatus = () => { // show notification if balance is too low useEffect(() => { if (!isBalanceLoaded) return; - if (!safeBalance) return; if (!showNotification) return; if (!storeState?.isInitialFunded) return; - if (safeBalance.ETH < LOW_BALANCE && !isLowBalanceNotificationShown) { + if (isLowBalance && !isLowBalanceNotificationShown) { showNotification('Trading balance is too low.'); setIsLowBalanceNotificationShown(true); } // If it has already been shown and the balance has increased, // should show the notification again if it goes below the threshold. - if (safeBalance.ETH >= LOW_BALANCE && isLowBalanceNotificationShown) { + if (!isLowBalance && isLowBalanceNotificationShown) { setIsLowBalanceNotificationShown(false); } }, [ isBalanceLoaded, isLowBalanceNotificationShown, - safeBalance, + isLowBalance, showNotification, storeState?.isInitialFunded, ]); const status = useMemo(() => { - if (!safeBalance || safeBalance.ETH < LOW_BALANCE) { + if (isLowBalance) { return { statusName: 'Too low', StatusComponent: EmptyDot }; } return { statusName: 'Fine', StatusComponent: FineDot }; - }, [safeBalance]); + }, [isLowBalance]); const { statusName, StatusComponent } = status; return ( diff --git a/frontend/components/Main/MainHeader/AgentButton/index.tsx b/frontend/components/Main/MainHeader/AgentButton/index.tsx index 356a45c12..42c060200 100644 --- a/frontend/components/Main/MainHeader/AgentButton/index.tsx +++ b/frontend/components/Main/MainHeader/AgentButton/index.tsx @@ -4,7 +4,6 @@ import { useCallback, useMemo } from 'react'; import { Chain, DeploymentStatus } from '@/client'; import { COLOR } from '@/constants/colors'; -import { LOW_BALANCE } from '@/constants/thresholds'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useServices } from '@/hooks/useServices'; @@ -101,6 +100,7 @@ const AgentNotRunningButton = () => { const { setIsPaused: setIsBalancePollingPaused, safeBalance, + isLowBalance, totalOlasStakedBalance, totalEthBalance, } = useBalance(); @@ -194,7 +194,7 @@ const AgentNotRunningButton = () => { const isServiceInactive = serviceStatus === DeploymentStatus.BUILT || serviceStatus === DeploymentStatus.STOPPED; - if (isServiceInactive && safeBalance && safeBalance.ETH < LOW_BALANCE) { + if (isServiceInactive && isLowBalance) { return false; } @@ -224,7 +224,7 @@ const AgentNotRunningButton = () => { serviceStatus, storeState?.isInitialFunded, totalEthBalance, - safeBalance, + isLowBalance, ]); const buttonProps: ButtonProps = { diff --git a/frontend/components/Main/MainHeader/index.tsx b/frontend/components/Main/MainHeader/index.tsx index 78ffde06f..7dbd5560d 100644 --- a/frontend/components/Main/MainHeader/index.tsx +++ b/frontend/components/Main/MainHeader/index.tsx @@ -2,7 +2,6 @@ import { Flex } from 'antd'; import { useCallback, useEffect, useState } from 'react'; import { DeploymentStatus } from '@/client'; -import { LOW_BALANCE } from '@/constants/thresholds'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useServices } from '@/hooks/useServices'; @@ -12,12 +11,12 @@ import { AgentHead } from './AgentHead'; import { FirstRunModal } from './FirstRunModal'; const useSetupTrayIcon = () => { - const { safeBalance } = useBalance(); + const { isLowBalance } = useBalance(); const { serviceStatus } = useServices(); const { setTrayIcon } = useElectronApi(); useEffect(() => { - if (safeBalance && safeBalance.ETH < LOW_BALANCE) { + if (isLowBalance) { setTrayIcon?.('low-gas'); } else if (serviceStatus === DeploymentStatus.DEPLOYED) { setTrayIcon?.('running'); @@ -26,7 +25,7 @@ const useSetupTrayIcon = () => { } else if (serviceStatus === DeploymentStatus.BUILT) { setTrayIcon?.('logged-out'); } - }, [safeBalance, serviceStatus, setTrayIcon]); + }, [isLowBalance, serviceStatus, setTrayIcon]); return null; }; diff --git a/frontend/components/Main/MainOlasBalance.tsx b/frontend/components/Main/MainOlasBalance.tsx index fa6d87b9b..9b11ebec7 100644 --- a/frontend/components/Main/MainOlasBalance.tsx +++ b/frontend/components/Main/MainOlasBalance.tsx @@ -122,13 +122,12 @@ const MainOlasBalanceAlert = styled.div` `; const LowTradingBalanceAlert = () => { - const { isBalanceLoaded, safeBalance } = useBalance(); + const { isBalanceLoaded, isLowBalance } = useBalance(); const { storeState } = useStore(); if (!isBalanceLoaded) return null; - if (!safeBalance) return null; if (!storeState?.isInitialFunded) return; - if (safeBalance.ETH >= LOW_BALANCE) return null; + if (!isLowBalance) return null; return ( diff --git a/frontend/constants/thresholds.ts b/frontend/constants/thresholds.ts index fb5ab3515..59d9dde02 100644 --- a/frontend/constants/thresholds.ts +++ b/frontend/constants/thresholds.ts @@ -7,4 +7,5 @@ export const MIN_ETH_BALANCE_THRESHOLDS = { }, }; +export const LOW_AGENT_BALANCE = 0.5; export const LOW_BALANCE = 2; diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 12c5400ec..9e8cef062 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -16,6 +16,7 @@ import { useInterval } from 'usehooks-ts'; import { Wallet } from '@/client'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { LOW_AGENT_BALANCE, LOW_BALANCE } from '@/constants/thresholds'; import { TOKENS } from '@/constants/tokens'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { Token } from '@/enums/Token'; @@ -43,6 +44,7 @@ export const BalanceContext = createContext<{ safeBalance?: ValueOf; totalEthBalance?: number; totalOlasBalance?: number; + isLowBalance: boolean; wallets?: Wallet[]; walletBalances: WalletAddressNumberRecord; updateBalances: () => Promise; @@ -58,6 +60,7 @@ export const BalanceContext = createContext<{ safeBalance: undefined, totalEthBalance: undefined, totalOlasBalance: undefined, + isLowBalance: false, wallets: undefined, walletBalances: {}, updateBalances: async () => {}, @@ -195,6 +198,22 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { () => masterSafeAddress && walletBalances[masterSafeAddress], [masterSafeAddress, walletBalances], ); + const agentSafeBalance = useMemo( + () => + services?.[0]?.chain_data?.multisig && + walletBalances[services[0].chain_data.multisig], + [services, walletBalances], + ); + const isLowBalance = useMemo(() => { + if (!safeBalance || !agentSafeBalance) return false; + if ( + safeBalance.ETH < LOW_BALANCE && + // Need to check agentSafe balance as well, because it's auto-funded from safeBalance + agentSafeBalance.ETH < LOW_AGENT_BALANCE + ) + return true; + return false; + }, [safeBalance, agentSafeBalance]); useInterval( () => { @@ -215,6 +234,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { safeBalance, totalEthBalance, totalOlasBalance, + isLowBalance, wallets, walletBalances, updateBalances, From b4d90a1f94feaeb1aa0c5189d2e83a73cd37e23b Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 14 Aug 2024 10:13:31 +0100 Subject: [PATCH 14/99] feat: Update enum names in PageState.ts and usePageState.ts --- frontend/components/Alert/index.tsx | 2 +- .../index.tsx | 4 +- .../IncentiveProgramSection/index.tsx | 131 ---------------- .../Incentives/WhatAreIncentivePrograms.tsx | 15 -- .../MainPage/MainHeader/FirstRunModal.tsx | 58 +++++++ .../header/AgentButton.tsx} | 27 +++- .../header}/AgentHead.tsx | 0 .../header/CannotStartAgentPopover.tsx} | 2 +- .../header}/constants.ts | 0 .../MainHeader => MainPage/header}/index.tsx | 2 +- .../components/{Main => MainPage}/index.tsx | 26 +-- .../modals}/FirstRunModal.tsx | 0 .../MainPage/modals/MigrationModal.tsx | 57 +++++++ .../sections/AddFundsSection.tsx} | 8 +- .../sections/GasBalanceSection.tsx} | 4 +- .../sections/KeepAgentRunningSection.tsx} | 8 +- .../sections/NeedsFundsSection.tsx} | 8 +- .../sections/NewIncentiveAlertSection.tsx} | 10 +- .../sections/OlasBalanceSection.tsx} | 8 +- .../sections/RewardsSection.tsx} | 4 +- .../IncentiveProgramBadge.tsx | 0 .../IncentiveProgramSection/alerts.tsx | 84 ++++++++++ .../IncentiveProgramSection/index.tsx | 148 ++++++++++++++++++ .../WhatAreStakingContracts.tsx | 36 +++++ .../index.tsx | 4 +- .../AddBackupWalletPage.tsx} | 2 +- .../DebugInfoSection.tsx} | 2 +- .../SettingsPage/StakingContractSection.tsx | 28 ++++ .../{Settings => SettingsPage}/index.tsx | 24 +-- .../Create/SetupBackupSigner.tsx | 0 .../Create/SetupCreateHeader.tsx | 0 .../Create/SetupCreateSafe.tsx | 4 +- .../Create/SetupEoaFunding.tsx | 6 +- .../Create/SetupPassword.tsx | 0 .../Create/SetupSeedPhrase.tsx | 0 .../{Setup => SetupPage}/SetupRestore.tsx | 0 .../{Setup => SetupPage}/SetupWelcome.tsx | 4 +- .../components/{Setup => SetupPage}/index.tsx | 0 frontend/context/PageStateProvider.tsx | 10 +- frontend/enums/PageState.ts | 4 +- frontend/hooks/useModals.ts | 11 ++ frontend/hooks/usePageState.ts | 4 +- frontend/hooks/useStakingProgram.ts | 36 +++++ frontend/pages/index.tsx | 18 +-- 44 files changed, 567 insertions(+), 232 deletions(-) rename frontend/components/{HelpAndSupport => HelpAndSupportPage}/index.tsx (97%) delete mode 100644 frontend/components/Incentives/IncentiveProgramSection/index.tsx delete mode 100644 frontend/components/Incentives/WhatAreIncentivePrograms.tsx create mode 100644 frontend/components/MainPage/MainHeader/FirstRunModal.tsx rename frontend/components/{Main/MainHeader/AgentButton/index.tsx => MainPage/header/AgentButton.tsx} (92%) rename frontend/components/{Main/MainHeader => MainPage/header}/AgentHead.tsx (100%) rename frontend/components/{Main/MainHeader/CannotStartAgent.tsx => MainPage/header/CannotStartAgentPopover.tsx} (98%) rename frontend/components/{Main/MainHeader => MainPage/header}/constants.ts (100%) rename frontend/components/{Main/MainHeader => MainPage/header}/index.tsx (96%) rename frontend/components/{Main => MainPage}/index.tsx (64%) rename frontend/components/{Main/MainHeader => MainPage/modals}/FirstRunModal.tsx (100%) create mode 100644 frontend/components/MainPage/modals/MigrationModal.tsx rename frontend/components/{Main/MainAddFunds.tsx => MainPage/sections/AddFundsSection.tsx} (96%) rename frontend/components/{Main/MainGasBalance.tsx => MainPage/sections/GasBalanceSection.tsx} (97%) rename frontend/components/{Main/KeepAgentRunning.tsx => MainPage/sections/KeepAgentRunningSection.tsx} (83%) rename frontend/components/{Main/MainNeedsFunds.tsx => MainPage/sections/NeedsFundsSection.tsx} (94%) rename frontend/components/{Main/NewIncentiveAlert.tsx => MainPage/sections/NewIncentiveAlertSection.tsx} (74%) rename frontend/components/{Main/MainOlasBalance.tsx => MainPage/sections/OlasBalanceSection.tsx} (97%) rename frontend/components/{Main/MainRewards.tsx => MainPage/sections/RewardsSection.tsx} (97%) rename frontend/components/{Incentives => ManageStakingPage}/IncentiveProgramSection/IncentiveProgramBadge.tsx (100%) create mode 100644 frontend/components/ManageStakingPage/IncentiveProgramSection/alerts.tsx create mode 100644 frontend/components/ManageStakingPage/IncentiveProgramSection/index.tsx create mode 100644 frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx rename frontend/components/{Incentives => ManageStakingPage}/index.tsx (93%) rename frontend/components/{Settings/SettingsAddBackupWallet.tsx => SettingsPage/AddBackupWalletPage.tsx} (97%) rename frontend/components/{Settings/DebugInfoCard.tsx => SettingsPage/DebugInfoSection.tsx} (99%) create mode 100644 frontend/components/SettingsPage/StakingContractSection.tsx rename frontend/components/{Settings => SettingsPage}/index.tsx (85%) rename frontend/components/{Setup => SetupPage}/Create/SetupBackupSigner.tsx (100%) rename frontend/components/{Setup => SetupPage}/Create/SetupCreateHeader.tsx (100%) rename frontend/components/{Setup => SetupPage}/Create/SetupCreateSafe.tsx (96%) rename frontend/components/{Setup => SetupPage}/Create/SetupEoaFunding.tsx (98%) rename frontend/components/{Setup => SetupPage}/Create/SetupPassword.tsx (100%) rename frontend/components/{Setup => SetupPage}/Create/SetupSeedPhrase.tsx (100%) rename frontend/components/{Setup => SetupPage}/SetupRestore.tsx (100%) rename frontend/components/{Setup => SetupPage}/SetupWelcome.tsx (98%) rename frontend/components/{Setup => SetupPage}/index.tsx (100%) create mode 100644 frontend/hooks/useModals.ts create mode 100644 frontend/hooks/useStakingProgram.ts diff --git a/frontend/components/Alert/index.tsx b/frontend/components/Alert/index.tsx index 3cadd98b7..5a0222108 100644 --- a/frontend/components/Alert/index.tsx +++ b/frontend/components/Alert/index.tsx @@ -14,7 +14,7 @@ const icons = { error: , }; -export const Alert = ({ +export const CustomAlert = ({ type, fullWidth, ...rest diff --git a/frontend/components/HelpAndSupport/index.tsx b/frontend/components/HelpAndSupportPage/index.tsx similarity index 97% rename from frontend/components/HelpAndSupport/index.tsx rename to frontend/components/HelpAndSupportPage/index.tsx index 278246e9e..1aec818ac 100644 --- a/frontend/components/HelpAndSupport/index.tsx +++ b/frontend/components/HelpAndSupportPage/index.tsx @@ -4,7 +4,7 @@ import { useCallback, useEffect, useState } from 'react'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { FAQ_URL, SUPPORT_URL } from '@/constants/urls'; -import { PageState } from '@/enums/PageState'; +import { Pages } from '@/enums/PageState'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useLogs } from '@/hooks/useLogs'; import { usePageState } from '@/hooks/usePageState'; @@ -78,7 +78,7 @@ export const HelpAndSupport = () => { - - ); -}; diff --git a/frontend/components/Incentives/WhatAreIncentivePrograms.tsx b/frontend/components/Incentives/WhatAreIncentivePrograms.tsx deleted file mode 100644 index 3fd179058..000000000 --- a/frontend/components/Incentives/WhatAreIncentivePrograms.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { RightOutlined } from '@ant-design/icons'; -import { Flex, Typography } from 'antd'; - -import { CardSection } from '../styled/CardSection'; - -export const WhatAreIncentiveProgramsSection = () => { - return ( - - - - What are incentive programs? - - - ); -}; diff --git a/frontend/components/MainPage/MainHeader/FirstRunModal.tsx b/frontend/components/MainPage/MainHeader/FirstRunModal.tsx new file mode 100644 index 000000000..73f017d70 --- /dev/null +++ b/frontend/components/MainPage/MainHeader/FirstRunModal.tsx @@ -0,0 +1,58 @@ +import { Button, Flex, Modal, Typography } from 'antd'; +import Image from 'next/image'; +import { FC } from 'react'; + +import { useServiceTemplates } from '@/hooks/useServiceTemplates'; +import { getMinimumStakedAmountRequired } from '@/utils/service'; + +type FirstRunModalProps = { open: boolean; onClose: () => void }; + +export const FirstRunModal: FC = ({ open, onClose }) => { + const { getServiceTemplates } = useServiceTemplates(); + + if (!open) return null; + + const minimumStakedAmountRequired = getMinimumStakedAmountRequired( + getServiceTemplates()[0], + ); + + return ( + + Got it + , + ]} + > + + OLAS logo + + + {`Your agent is running and you've staked ${minimumStakedAmountRequired} OLAS!`} + + + Your agent is working towards earning rewards. + + + Pearl is designed to make it easy for you to earn staking rewards every + day. Simply leave the app and agent running in the background for ~1hr a + day. + + + ); +}; diff --git a/frontend/components/Main/MainHeader/AgentButton/index.tsx b/frontend/components/MainPage/header/AgentButton.tsx similarity index 92% rename from frontend/components/Main/MainHeader/AgentButton/index.tsx rename to frontend/components/MainPage/header/AgentButton.tsx index 356a45c12..7f689d92a 100644 --- a/frontend/components/Main/MainHeader/AgentButton/index.tsx +++ b/frontend/components/MainPage/header/AgentButton.tsx @@ -10,6 +10,7 @@ import { useElectronApi } from '@/hooks/useElectronApi'; import { useServices } from '@/hooks/useServices'; import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { useStakingContractInfo } from '@/hooks/useStakingContractInfo'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; import { useStore } from '@/hooks/useStore'; import { useWallet } from '@/hooks/useWallet'; import { ServicesService } from '@/service/Services'; @@ -17,10 +18,10 @@ import { WalletService } from '@/service/Wallet'; import { getMinimumStakedAmountRequired } from '@/utils/service'; import { - CannotStartAgent, CannotStartAgentDueToUnexpectedError, -} from '../CannotStartAgent'; -import { requiredGas, requiredOlas } from '../constants'; + CannotStartAgentPopover, +} from './CannotStartAgentPopover'; +import { requiredGas, requiredOlas } from './constants'; const { Text } = Typography; @@ -239,7 +240,19 @@ const AgentNotRunningButton = () => { return ; }; +const MigratingButton = () => { + return ( + + + + ); +}; + export const AgentButton = () => { + const { isMigrating } = useStakingProgram(); const { service, serviceStatus, hasInitialLoaded } = useServices(); const { isEligibleForStaking, isAgentEvicted } = useStakingContractInfo(); @@ -248,6 +261,10 @@ export const AgentButton = () => { return , + ]} + > + + {/* Robot head */} + + Pearl agent head + + + You switched staking contract succesfully! + + + Your agent is now staked on {currentStakingProgram.name}. + + {/* TODO: Add relevant block explorer domain */} + + View full contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + + ); +}; diff --git a/frontend/components/Main/MainAddFunds.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx similarity index 96% rename from frontend/components/Main/MainAddFunds.tsx rename to frontend/components/MainPage/sections/AddFundsSection.tsx index 06fd3d4dc..97bf85641 100644 --- a/frontend/components/Main/MainAddFunds.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -22,8 +22,8 @@ import { Address } from '@/types/Address'; import { copyToClipboard } from '@/utils/copyToClipboard'; import { truncateAddress } from '@/utils/truncate'; -import { Alert } from '../Alert'; -import { CardSection } from '../styled/CardSection'; +import { CustomAlert } from '../../Alert'; +import { CardSection } from '../../styled/CardSection'; const { Text } = Typography; @@ -33,7 +33,7 @@ const CustomizedCardSection = styled(CardSection)<{ border?: boolean }>` } `; -export const MainAddFunds = () => { +export const AddFundsSection = () => { const [isAddFundsVisible, setIsAddFundsVisible] = useState(false); const { masterSafeAddress } = useWallet(); @@ -92,7 +92,7 @@ export const MainAddFunds = () => { const AddFundsWarningAlertSection = () => ( - { +export const GasBalanceSection = () => { const { masterSafeAddress } = useWallet(); const { isBalanceLoaded } = useBalance(); diff --git a/frontend/components/Main/KeepAgentRunning.tsx b/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx similarity index 83% rename from frontend/components/Main/KeepAgentRunning.tsx rename to frontend/components/MainPage/sections/KeepAgentRunningSection.tsx index 1cc98b333..90803c2f1 100644 --- a/frontend/components/Main/KeepAgentRunning.tsx +++ b/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx @@ -4,14 +4,14 @@ import { DeploymentStatus } from '@/client'; import { useServices } from '@/hooks/useServices'; import { useStore } from '@/hooks/useStore'; -import { Alert } from '../Alert'; -import { CardSection } from '../styled/CardSection'; +import { CustomAlert } from '../../Alert'; +import { CardSection } from '../../styled/CardSection'; const { Text } = Typography; const COVER_BLOCK_BORDERS_STYLE = { marginBottom: '-1px' }; -export const KeepAgentRunning = () => { +export const KeepAgentRunningSection = () => { const { storeState } = useStore(); const { serviceStatus } = useServices(); @@ -20,7 +20,7 @@ export const KeepAgentRunning = () => { return ( - { return ( - + ); }; diff --git a/frontend/components/Main/NewIncentiveAlert.tsx b/frontend/components/MainPage/sections/NewIncentiveAlertSection.tsx similarity index 74% rename from frontend/components/Main/NewIncentiveAlert.tsx rename to frontend/components/MainPage/sections/NewIncentiveAlertSection.tsx index c38b870dd..b99c4f1a6 100644 --- a/frontend/components/Main/NewIncentiveAlert.tsx +++ b/frontend/components/MainPage/sections/NewIncentiveAlertSection.tsx @@ -1,10 +1,10 @@ import { Button, Flex, Typography } from 'antd'; -import { PageState } from '@/enums/PageState'; +import { Pages } from '@/enums/PageState'; import { usePageState } from '@/hooks/usePageState'; -import { Alert } from '../Alert'; -import { CardSection } from '../styled/CardSection'; +import { CustomAlert } from '../../Alert'; +import { CardSection } from '../../styled/CardSection'; const { Text } = Typography; @@ -13,7 +13,7 @@ export const NewIncentiveAlert = () => { return ( - { diff --git a/frontend/components/Main/MainOlasBalance.tsx b/frontend/components/MainPage/sections/OlasBalanceSection.tsx similarity index 97% rename from frontend/components/Main/MainOlasBalance.tsx rename to frontend/components/MainPage/sections/OlasBalanceSection.tsx index 28e0170a4..a991ec711 100644 --- a/frontend/components/Main/MainOlasBalance.tsx +++ b/frontend/components/MainPage/sections/OlasBalanceSection.tsx @@ -3,7 +3,7 @@ import { Button, Flex, Skeleton, Tooltip, Typography } from 'antd'; import { useMemo } from 'react'; import styled from 'styled-components'; -import { Alert } from '@/components/Alert'; +import { CustomAlert } from '@/components/Alert'; import { COLOR } from '@/constants/colors'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { LOW_BALANCE } from '@/constants/thresholds'; @@ -13,7 +13,7 @@ import { useReward } from '@/hooks/useReward'; import { useStore } from '@/hooks/useStore'; import { balanceFormat } from '@/utils/numberFormatters'; -import { CardSection } from '../styled/CardSection'; +import { CardSection } from '../../styled/CardSection'; const { Text, Title } = Typography; const Balance = styled.span` @@ -130,7 +130,7 @@ const LowTradingBalanceAlert = () => { return ( - { return ( - ( + + + Add funds to your account to meet the program requirements. + + + Your current OLAS balance: {totalOlasBalance} OLAS + + + Your current trading balance: {totalEthBalance} XDAI + + + } + /> +); +{ + /* No jobs available alert */ +} + +export const AlertNoSlots = () => ( + + No slots currently available - try again later. + + } + /> +); + +export const AlertUpdateToMigrate = () => ( + + {/* + TODO: Define version requirement in some JSON store? + How do we access this date on a previous version? + */} + + This incentive program is available for users who have the app version + rc105 or higher. + + {/* TODO: make current version accessible via Electron or Env? */} + Current app version: rc97 + {/* TODO: trigger update through IPC */} + + Update Pearl to the latest version {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + } + /> +); + +export const AlertCantMigrateDefault = () => ( + +); diff --git a/frontend/components/ManageStakingPage/IncentiveProgramSection/index.tsx b/frontend/components/ManageStakingPage/IncentiveProgramSection/index.tsx new file mode 100644 index 000000000..4a17a5a4b --- /dev/null +++ b/frontend/components/ManageStakingPage/IncentiveProgramSection/index.tsx @@ -0,0 +1,148 @@ +import { Button, Flex, theme, Typography } from 'antd'; +import { useMemo } from 'react'; + +import { CardSection } from '@/components/styled/CardSection'; +import { UNICODE_SYMBOLS } from '@/constants/symbols'; +import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; +import { useBalance } from '@/hooks/useBalance'; +import { Address } from '@/types/Address'; +import { IncentiveProgram } from '@/types/IncentiveProgram'; + +import { + AlertInsufficientMigrationFunds, + AlertNoSlots, + AlertUpdateToMigrate, +} from './alerts'; +import { IncentiveProgramTag } from './IncentiveProgramBadge'; + +const { useToken } = theme; + +const ProgramTitle = ({ + name, + status, +}: { + name: string; + status: IncentiveProgramStatus; +}) => ( + + {name} + + +); + +const ProgramDetailsLink = ({ address }: { address: Address }) => { + const blockExplorerLink = `https://blockExplorer.com/poa/xdai/address/${address}`; + return ( + + Contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} + + ); +}; + +const HorizontalGreyLine = () => ( + +); + +export const IncentiveProgramSection = ({ + program, +}: { + program: IncentiveProgram; +}) => { + const { token } = useToken(); + const { totalOlasBalance, totalEthBalance, isBalanceLoaded } = useBalance(); + + const isEnoughSlots = false; //program.slots > 0; + const isEnoughOlas = false; // totalOlasBalance; + const isEnoughEth = false; // totalEthBalance; + const isAppVersionCompatible = false; // program.appVersion === 'rc105'; + + const isMigratable = + program.status !== IncentiveProgramStatus.Deprecated && + program.status !== IncentiveProgramStatus.Selected && + isBalanceLoaded && + isEnoughSlots && + isEnoughOlas && + isEnoughEth && + isAppVersionCompatible; + + const alertCantMigrate = useMemo(() => { + if ( + program.status === IncentiveProgramStatus.Deprecated || + program.status === IncentiveProgramStatus.Selected + ) { + return; + } + + if (!isBalanceLoaded) { + return; + } + + if (isEnoughSlots) { + return ; + } + + if (!isEnoughOlas || !isEnoughEth) { + return ( + + ); + } + + if (!isAppVersionCompatible) { + return ; + } + + if (!isMigratable) { + return; + } + }, [ + isAppVersionCompatible, + isBalanceLoaded, + isEnoughEth, + isEnoughOlas, + isEnoughSlots, + isMigratable, + program.status, + totalEthBalance, + totalOlasBalance, + ]); + + return ( + + {/* Title */} + + + + + {/* Rewards per work period */} + + Rewards per work period + + {`0.25 OLAS`} + + {/* Required Olas */} + + Required OLAS for staking + + {`20 OLAS`} + + {/* "Can't migrate" Alert */} + {alertCantMigrate} + {/* Switch to program button */} + + + ); +}; diff --git a/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx b/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx new file mode 100644 index 000000000..21826c604 --- /dev/null +++ b/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx @@ -0,0 +1,36 @@ +import { Collapse, Flex, Typography } from 'antd'; + +import { CardSection } from '../styled/CardSection'; + +const collapseItems = [ + { + key: 1, + label: 'What are incentive programs?', + children: ( + + + When your agent goes to work, it participates in staking contracts. + + + Staking contracts define what the agent needs to do, how much OLAS + needs to be staked etc. + + + Your agent can only participate in one staking contract at a time. + + + You need to run your agent for max 1 hour a day, regardless of the + staking contract. + + + ), + }, +]; + +export const WhatAreIncentiveProgramsSection = () => { + return ( + + + + ); +}; diff --git a/frontend/components/Incentives/index.tsx b/frontend/components/ManageStakingPage/index.tsx similarity index 93% rename from frontend/components/Incentives/index.tsx rename to frontend/components/ManageStakingPage/index.tsx index 11d998bcf..ef3fe0fbd 100644 --- a/frontend/components/Incentives/index.tsx +++ b/frontend/components/ManageStakingPage/index.tsx @@ -1,7 +1,7 @@ import { CloseOutlined, SettingOutlined } from '@ant-design/icons'; import { Button, Card, Flex } from 'antd'; -import { PageState } from '@/enums/PageState'; +import { Pages } from '@/enums/PageState'; import { usePageState } from '@/hooks/usePageState'; import { IncentiveProgram } from '@/types/IncentiveProgram'; @@ -46,7 +46,7 @@ export const Incentives = () => { + + ); +}; diff --git a/frontend/components/Settings/index.tsx b/frontend/components/SettingsPage/index.tsx similarity index 85% rename from frontend/components/Settings/index.tsx rename to frontend/components/SettingsPage/index.tsx index 81a0a0160..3c657e680 100644 --- a/frontend/components/Settings/index.tsx +++ b/frontend/components/SettingsPage/index.tsx @@ -4,18 +4,19 @@ import Link from 'next/link'; import { useMemo } from 'react'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { PageState } from '@/enums/PageState'; +import { Pages } from '@/enums/PageState'; import { SettingsScreen } from '@/enums/SettingsScreen'; import { useMasterSafe } from '@/hooks/useMasterSafe'; import { usePageState } from '@/hooks/usePageState'; import { useSettings } from '@/hooks/useSettings'; import { truncateAddress } from '@/utils/truncate'; -import { Alert } from '../Alert'; +import { CustomAlert } from '../Alert'; import { CardTitle } from '../Card/CardTitle'; import { CardSection } from '../styled/CardSection'; -import { DebugInfoCard } from './DebugInfoCard'; -import { SettingsAddBackupWallet } from './SettingsAddBackupWallet'; +import { AddBackupWalletPage } from './AddBackupWalletPage'; +import { DebugInfoSection } from './DebugInfoSection'; +import { StakingContractSection } from './StakingContractSection'; const { Text, Paragraph } = Typography; @@ -37,7 +38,7 @@ export const Settings = () => { case SettingsScreen.Main: return ; case SettingsScreen.AddBackupWallet: - return ; + return ; default: return null; } @@ -64,17 +65,18 @@ const SettingsMain = () => { - - ); -}; diff --git a/frontend/components/ManageStakingPage/StakingContract/StakingContractTag.tsx b/frontend/components/ManageStakingPage/StakingContract/StakingContractTag.tsx new file mode 100644 index 000000000..9233845fa --- /dev/null +++ b/frontend/components/ManageStakingPage/StakingContract/StakingContractTag.tsx @@ -0,0 +1,18 @@ +import { Tag } from 'antd'; + +import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; + +export const StakingContractTag = ({ + status, +}: { + status: IncentiveProgramStatus; +}) => { + if (status === IncentiveProgramStatus.New) { + return New; + } else if (status === IncentiveProgramStatus.Selected) { + return Selected; + } else if (status === IncentiveProgramStatus.Deprecated) { + return Deprecated; + } + return null; +}; diff --git a/frontend/components/ManageStakingPage/StakingContract/alerts.tsx b/frontend/components/ManageStakingPage/StakingContract/alerts.tsx new file mode 100644 index 000000000..f2c1cf6cd --- /dev/null +++ b/frontend/components/ManageStakingPage/StakingContract/alerts.tsx @@ -0,0 +1,62 @@ +import { Flex, Typography } from 'antd'; + +import { CustomAlert } from '@/components/Alert'; +import { UNICODE_SYMBOLS } from '@/constants/symbols'; + +const { Text } = Typography; + +export const AlertInsufficientMigrationFunds = ({ + totalOlasBalance, +}: { + totalOlasBalance: number; +}) => ( + + + Insufficient amount of funds to switch + + + Add funds to your account to meet the program requirements. + + Your current OLAS balance:{' '} + {totalOlasBalance} OLAS + + + } + /> +); + +export const AlertNoSlots = () => ( + No slots currently available - try again later.} + /> +); + +export const AlertUpdateToMigrate = () => ( + + App update required + + {/* + TODO: Define version requirement in some JSON store? + How do we access this date on a previous version? + */} + + Update Pearl to the latest version to switch to the staking contract. + + {/* TODO: trigger update through IPC */} + + Update Pearl to the latest version {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + } + /> +); diff --git a/frontend/components/ManageStakingPage/StakingContract/index.tsx b/frontend/components/ManageStakingPage/StakingContract/index.tsx new file mode 100644 index 000000000..0153d4dba --- /dev/null +++ b/frontend/components/ManageStakingPage/StakingContract/index.tsx @@ -0,0 +1,139 @@ +import { Button, Divider, Flex, theme, Typography } from 'antd'; +import { useMemo } from 'react'; +import styled from 'styled-components'; + +import { CardSection } from '@/components/styled/CardSection'; +import { UNICODE_SYMBOLS } from '@/constants/symbols'; +import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; +import { useBalance } from '@/hooks/useBalance'; +import { IncentiveProgram } from '@/types/IncentiveProgram'; + +import { + AlertInsufficientMigrationFunds, + AlertNoSlots, + AlertUpdateToMigrate, +} from './alerts'; +import { StakingContractTag } from './StakingContractTag'; + +const { Text } = Typography; + +const { useToken } = theme; + +const CustomDivider = styled(Divider)` + flex: auto; + width: max-content; + min-width: 0; + margin: 0; +`; + +const ContractParameter = ({ + label, + value, +}: { + label: string; + value: string; +}) => ( + + {label} + + {value} + +); + +export const StakingContract = ({ + contract, +}: { + contract: IncentiveProgram; +}) => { + const { token } = useToken(); + const { totalOlasBalance, isBalanceLoaded } = useBalance(); + + const isDeprecated = contract.status === IncentiveProgramStatus.Deprecated; + const isSelected = contract.status === IncentiveProgramStatus.Selected; + + const isEnoughOlas = useMemo(() => { + if (totalOlasBalance === undefined) return false; + return totalOlasBalance > contract.requiredOlasForStaking; + }, [totalOlasBalance, contract.requiredOlasForStaking]); + const isAppVersionCompatible = true; // contract.appVersion === 'rc105'; + + const isMigratable = + !isDeprecated && + !isSelected && + isBalanceLoaded && + contract.isEnoughSlots && + isEnoughOlas && + isAppVersionCompatible; + + const cantMigrateAlert = useMemo(() => { + if (isDeprecated || isSelected || !isBalanceLoaded) { + return null; + } + + if (!contract.isEnoughSlots) { + return ; + } + + if (!isEnoughOlas) { + return ( + + ); + } + + if (!isAppVersionCompatible) { + return ; + } + }, [ + isDeprecated, + isSelected, + isBalanceLoaded, + totalOlasBalance, + contract.isEnoughSlots, + isEnoughOlas, + isAppVersionCompatible, + ]); + + return ( + + {/* Title */} + + {`${contract.name} contract`} + + {isMigratable && ( + + Contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} + + )} + + {/* Contract details */} + + + {/* "Can't migrate" Alert */} + {cantMigrateAlert} + {/* Switch to program button */} + {!isSelected && ( + + )} + + ); +}; diff --git a/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx b/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx index 21826c604..f06f2ace5 100644 --- a/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx +++ b/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx @@ -2,35 +2,42 @@ import { Collapse, Flex, Typography } from 'antd'; import { CardSection } from '../styled/CardSection'; +const { Text } = Typography; + const collapseItems = [ { key: 1, - label: 'What are incentive programs?', + label: What are staking contracts?, children: ( - - + + When your agent goes to work, it participates in staking contracts. - - + + Staking contracts define what the agent needs to do, how much OLAS needs to be staked etc. - - + + Your agent can only participate in one staking contract at a time. - - + + You need to run your agent for max 1 hour a day, regardless of the staking contract. - + ), }, ]; -export const WhatAreIncentiveProgramsSection = () => { +export const WhatAreStakingContractsSection = () => { return ( - - + + ); }; diff --git a/frontend/components/ManageStakingPage/index.tsx b/frontend/components/ManageStakingPage/index.tsx index ef3fe0fbd..364def9cb 100644 --- a/frontend/components/ManageStakingPage/index.tsx +++ b/frontend/components/ManageStakingPage/index.tsx @@ -1,47 +1,40 @@ -import { CloseOutlined, SettingOutlined } from '@ant-design/icons'; -import { Button, Card, Flex } from 'antd'; +import { CloseOutlined } from '@ant-design/icons'; +import { Button, Card } from 'antd'; +import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; import { Pages } from '@/enums/PageState'; import { usePageState } from '@/hooks/usePageState'; import { IncentiveProgram } from '@/types/IncentiveProgram'; import { CardTitle } from '../Card/CardTitle'; -import { IncentiveProgramSection } from './IncentiveProgramSection'; -import { WhatAreIncentiveProgramsSection } from './WhatAreIncentivePrograms'; +import { StakingContract } from './StakingContract'; +import { WhatAreStakingContractsSection } from './WhatAreStakingContracts'; -const IncentivesTitle = () => { - return ( - - - Settings - - } - /> - ); -}; - -const mockIncentivePrograms: IncentiveProgram[] = [ +const mockStakingContracts: IncentiveProgram[] = [ { - name: 'Incentive Program 1', - rewardsPerWorkPeriod: 100, - requiredOlasForStaking: 1000, + name: 'Pearl Beta', + rewardsPerWorkPeriod: 0.14, + requiredOlasForStaking: 40, + isEnoughSlots: true, + status: IncentiveProgramStatus.New, contractAddress: '0x1234567890', }, { - name: 'Incentive Program 2', - rewardsPerWorkPeriod: 200, - requiredOlasForStaking: 2000, + name: 'Pearl Alpha', + rewardsPerWorkPeriod: 0.047, + requiredOlasForStaking: 20, + isEnoughSlots: true, + status: IncentiveProgramStatus.Selected, contractAddress: '0x0987654321', }, ]; -export const Incentives = () => { +export const ManageStakingPage = () => { const { goto } = usePageState(); return ( } + title={} + bordered={false} extra={ diff --git a/frontend/pages/index.tsx b/frontend/pages/index.tsx index 1ad8084b4..0977107e7 100644 --- a/frontend/pages/index.tsx +++ b/frontend/pages/index.tsx @@ -7,6 +7,7 @@ import { Setup } from '@/components/SetupPage'; import { Pages } from '@/enums/PageState'; import { useElectronApi } from '@/hooks/useElectronApi'; import { usePageState } from '@/hooks/usePageState'; +import { ManageStakingPage } from '@/components/ManageStakingPage'; const DEFAULT_APP_HEIGHT = 700; @@ -42,6 +43,8 @@ export default function Home() { return ; case Pages.HelpAndSupport: return ; + case Pages.ManageStaking: + return ; default: return
; } diff --git a/frontend/styles/globals.scss b/frontend/styles/globals.scss index 13afcf16c..8e4dda2e4 100644 --- a/frontend/styles/globals.scss +++ b/frontend/styles/globals.scss @@ -124,6 +124,10 @@ button, input, select, textarea, .ant-input-suffix { margin-bottom: 16px !important; } +.ml-auto { + margin-left: auto !important; +} + .mb-auto { margin-bottom: auto !important; } diff --git a/frontend/types/IncentiveProgram.ts b/frontend/types/IncentiveProgram.ts index 4c04a97fe..e3d4a6c7a 100644 --- a/frontend/types/IncentiveProgram.ts +++ b/frontend/types/IncentiveProgram.ts @@ -6,6 +6,7 @@ export type IncentiveProgram = { name: string; rewardsPerWorkPeriod: number; requiredOlasForStaking: number; + isEnoughSlots: boolean; status: IncentiveProgramStatus; contractAddress: Address; }; From bf4d19651fb2bfc776032778667deeb3d5e49091 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 14 Aug 2024 18:16:16 +0200 Subject: [PATCH 27/99] fix: fund service --- operate/services/manage.py | 72 +++++++++++-------------------------- operate/services/service.py | 2 +- 2 files changed, 21 insertions(+), 53 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 57ed46c02..1deba892b 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -726,7 +726,6 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non chain_config = service.chain_configs[chain_id] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data - user_params = chain_config.chain_data.user_params keys = service.keys instances = [key.address for key in keys] wallet = self.wallet_manager.load(ledger_config.type) @@ -927,6 +926,9 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str, target_stak chain_config.chain_data.staked = True service.store() + current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + self.logger.info(f"{current_staking_program=}") + def unstake_service_on_chain(self, hash: str) -> None: """ Unbond service on-chain @@ -1013,14 +1015,19 @@ def fund_service( # pylint: disable=too-many-arguments ) -> None: """Fund service if required.""" service = self.load_or_create(hash=hash) - wallet = self.wallet_manager.load(ledger_type=service.ledger_config.type) - ledger_api = wallet.ledger_api(chain_type=service.ledger_config.chain, rpc=rpc) + chain_id = service.home_chain_id + chain_config = service.chain_configs[chain_id] + ledger_config = chain_config.ledger_config + chain_data = chain_config.chain_data + wallet = self.wallet_manager.load(ledger_config.type) + ledger_api = wallet.ledger_api(chain_type=ledger_config.chain, rpc=ledger_config.rpc) agent_fund_threshold = ( agent_fund_threshold - or service.chain_data.user_params.fund_requirements.agent + or chain_data.user_params.fund_requirements.agent ) for key in service.keys: + print(key.address) agent_balance = ledger_api.get_balance(address=key.address) self.logger.info(f"Agent {key.address} balance: {agent_balance}") self.logger.info(f"Required balance: {agent_fund_threshold}") @@ -1028,34 +1035,34 @@ def fund_service( # pylint: disable=too-many-arguments self.logger.info("Funding agents") to_transfer = ( agent_topup - or service.chain_data.user_params.fund_requirements.agent + or chain_data.user_params.fund_requirements.agent ) self.logger.info(f"Transferring {to_transfer} units to {key.address}") wallet.transfer( to=key.address, amount=int(to_transfer), - chain_type=service.ledger_config.chain, + chain_type=ledger_config.chain, from_safe=from_safe, ) - safe_balanace = ledger_api.get_balance(service.chain_data.multisig) + safe_balanace = ledger_api.get_balance(chain_data.multisig) safe_fund_treshold = ( - safe_fund_treshold or service.chain_data.user_params.fund_requirements.safe + safe_fund_treshold or chain_data.user_params.fund_requirements.safe ) - self.logger.info(f"Safe {service.chain_data.multisig} balance: {safe_balanace}") + self.logger.info(f"Safe {chain_data.multisig} balance: {safe_balanace}") self.logger.info(f"Required balance: {safe_fund_treshold}") if safe_balanace < safe_fund_treshold: self.logger.info("Funding safe") to_transfer = ( - safe_topup or service.chain_data.user_params.fund_requirements.safe + safe_topup or chain_data.user_params.fund_requirements.safe ) self.logger.info( - f"Transferring {to_transfer} units to {service.chain_data.multisig}" + f"Transferring {to_transfer} units to {chain_data.multisig}" ) wallet.transfer( - to=t.cast(str, service.chain_data.multisig), + to=t.cast(str, chain_data.multisig), amount=int(to_transfer), - chain_type=service.ledger_config.chain, + chain_type=ledger_config.chain, ) async def funding_job( @@ -1128,45 +1135,6 @@ def update_service( old_service = self.load_or_create( hash=old_hash, ) - # TODO code for updating service commented until safe swap transaction is implemented - # This is a temporary fix that will only work for services that have not started the - # update flow. Services having started the update flow must need to manually change - # the Safe owner to the Operator. - # ( # noqa: E800 - # self.unstake_service_on_chain_from_safe # noqa: E800 - # if from_safe # noqa: E800 - # else self.unstake_service_on_chain # noqa: E800 - # )( # noqa: E800 - # hash=old_hash, # noqa: E800 - # ) # noqa: E800 - # ( # noqa: E800 - # self.terminate_service_on_chain_from_safe # noqa: E800 - # if from_safe # noqa: E800 - # else self.terminate_service_on_chain # noqa: E800 - # )( # noqa: E800 - # hash=old_hash, # noqa: E800 - # ) # noqa: E800 - # ( # noqa: E800 - # self.unbond_service_on_chain_from_safe # noqa: E800 - # if from_safe # noqa: E800 - # else self.unbond_service_on_chain # noqa: E800 - # )( # noqa: E800 - # hash=old_hash, # noqa: E800 - # ) # noqa: E800 - - # owner, *_ = old_service.chain_data.instances # noqa: E800 - # if from_safe: # noqa: E800 - - # else: # noqa: E800 - # ocm = self.get_on_chain_manager(service=old_service) # noqa: E800 - # ocm.swap( # noqa: E800 - # service_id=old_service.chain_data.token, # noqa: E800 - # multisig=old_service.chain_data.multisig, # noqa: E800 - # owner_key=str( - # self.keys_manager.get(key=owner).private_key - # ), # noqa: E800 - # ) # noqa: E800 - new_service = self.load_or_create( hash=new_hash, rpc=rpc or old_service.ledger_config.rpc, diff --git a/operate/services/service.py b/operate/services/service.py index e2a3d8947..df00153fd 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -636,7 +636,7 @@ class Service(LocalResource): version: int hash: str keys: Keys - home_chain_id: int + home_chain_id: str chain_configs: ChainConfigs path: Path From cf1fdd7fb6857789e2b52a63c1d2c3005b56d08c Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 14 Aug 2024 18:17:31 +0200 Subject: [PATCH 28/99] fix: funding_job --- operate/services/manage.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 1deba892b..2d1b2ff5a 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -1074,6 +1074,9 @@ async def funding_job( """Start a background funding job.""" loop = loop or asyncio.get_event_loop() service = self.load_or_create(hash=hash) + chain_id = service.home_chain_id + chain_config = service.chain_configs[chain_id] + ledger_config = chain_config.ledger_config with ThreadPoolExecutor() as executor: while True: try: @@ -1081,7 +1084,7 @@ async def funding_job( executor, self.fund_service, hash, # Service hash - PUBLIC_RPCS[service.ledger_config.chain], # RPC + PUBLIC_RPCS[ledger_config.chain], # RPC 100000000000000000, # agent_topup 2000000000000000000, # safe_topup 50000000000000000, # agent_fund_threshold From 352b07d2ddf09a59767b19e15d2bfcc2ceba3d5f Mon Sep 17 00:00:00 2001 From: Atatakai Date: Wed, 14 Aug 2024 20:19:29 +0400 Subject: [PATCH 29/99] feat: update showing contract details ling logic --- .../components/ManageStakingPage/StakingContract/index.tsx | 4 +++- frontend/pages/index.tsx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContract/index.tsx b/frontend/components/ManageStakingPage/StakingContract/index.tsx index 0153d4dba..639835220 100644 --- a/frontend/components/ManageStakingPage/StakingContract/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContract/index.tsx @@ -107,7 +107,9 @@ export const StakingContract = ({ className="m-0" >{`${contract.name} contract`} - {isMigratable && ( + {!isSelected && ( + // here instead of isSelected we should check that the contract is not the old staking contract + // but the one from staking factory (if we want to open govern) Date: Wed, 14 Aug 2024 18:22:44 +0200 Subject: [PATCH 30/99] [no ci] chore: minor fixes --- operate/services/manage.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 2d1b2ff5a..8d970ee94 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -41,7 +41,6 @@ from operate.services.protocol import EthSafeTxBuilder, OnChainManager, StakingState from operate.services.service import ( ChainConfig, - ChainConfigs, DELETE_PREFIX, Deployment, NON_EXISTENT_TOKEN, @@ -1020,7 +1019,7 @@ def fund_service( # pylint: disable=too-many-arguments ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data wallet = self.wallet_manager.load(ledger_config.type) - ledger_api = wallet.ledger_api(chain_type=ledger_config.chain, rpc=ledger_config.rpc) + ledger_api = wallet.ledger_api(chain_type=ledger_config.chain, rpc=rpc if rpc else ledger_config.rpc) agent_fund_threshold = ( agent_fund_threshold or chain_data.user_params.fund_requirements.agent From e5c7d489adc27344ed9fbca458dfa57fa53b1cfd Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 14 Aug 2024 18:49:07 +0200 Subject: [PATCH 31/99] fix: staking flow --- operate/services/manage.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 8d970ee94..235b0ce0a 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -29,7 +29,6 @@ from concurrent.futures import ThreadPoolExecutor from pathlib import Path -import aiohttp # type: ignore import requests from aea.helpers.base import IPFSHash from aea.helpers.logging import setup_logger @@ -209,7 +208,6 @@ def _get_on_chain_hash(self, chain_config: ChainConfig) -> t.Optional[str]: f"Something went wrong while trying to get the code uri from IPFS: {res}" ) - def deploy_service_onchain( # pylint: disable=too-many-statements self, hash: str, @@ -362,7 +360,6 @@ def deploy_service_onchain( # pylint: disable=too-many-statements ) service.store() - def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too-many-locals self, hash: str, @@ -867,17 +864,19 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str, target_stak if not chain_config.chain_data.user_params.use_staking and can_unstake: self.logger.info("Use staking is set to false, but service is staked and can be unstaked. Unstaking...") self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) - return info = sftxb.info(token_id=chain_config.chain_data.token) chain_config.chain_data.on_chain_state = OnChainState(info["service_state"]) + staking_state = sftxb.staking_status( + service_id=chain_data.token, + staking_contract=current_staking_contract, + ) - if self._get_on_chain_state(chain_config=chain_config) == StakingState.EVICTED and can_unstake: + if staking_state == StakingState.EVICTED and can_unstake: self.logger.info(f"{chain_config.chain_data.token} has been evicted and can be unstaked. Unstaking...") self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) - return - if self._get_on_chain_state(chain_config=chain_config) == StakingState.STAKED and can_unstake and not ocm.staking_rewards_available(current_staking_contract): + if staking_state == StakingState.STAKED and can_unstake and not sftxb.staking_rewards_available(current_staking_contract): self.logger.info( f"There are no rewards available, {chain_config.chain_data.token} " f"is already staked and can be unstaked. " @@ -885,24 +884,24 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str, target_stak ) self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) - if self._get_on_chain_state(chain_config=chain_config) == StakingState.STAKED and current_staking_program != target_staking_contract and can_unstake: + if staking_state == StakingState.STAKED and current_staking_program != target_staking_contract and can_unstake: self.logger.info( f"{chain_config.chain_data.token} is already staked in a different staking program. " f"Unstaking..." ) self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) - state = sftxb.staking_status( + staking_state = sftxb.staking_status( service_id=chain_config.chain_data.token, staking_contract=target_staking_contract, ) if ( chain_config.chain_data.user_params.use_staking - and state == StakingState.UNSTAKED + and staking_state == StakingState.UNSTAKED and sftxb.staking_rewards_available(target_staking_contract) and sftxb.staking_slots_available(target_staking_contract) - and chain_config.chain_data.on_chain_state == OnChainState.DEPLOYED + and self._get_on_chain_state(chain_config=chain_config) == OnChainState.DEPLOYED ): self.logger.info(f"Approving staking: {chain_config.chain_data.token}") sftxb.new_tx().add( @@ -1026,7 +1025,6 @@ def fund_service( # pylint: disable=too-many-arguments ) for key in service.keys: - print(key.address) agent_balance = ledger_api.get_balance(address=key.address) self.logger.info(f"Agent {key.address} balance: {agent_balance}") self.logger.info(f"Required balance: {agent_fund_threshold}") From c46c86f63f54f2e433dbc4ad5f9733ab390a1aff Mon Sep 17 00:00:00 2001 From: Ardian Date: Wed, 14 Aug 2024 18:58:25 +0200 Subject: [PATCH 32/99] feat: add first time deploy --- operate/services/protocol.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/operate/services/protocol.py b/operate/services/protocol.py index 1382924e7..948a1776f 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -1136,6 +1136,7 @@ def get_deploy_data_from_safe( ledger_api=self.ledger_api, contract_address=self.contracts["service_manager"], ) + approve_hash_message = None if reuse_multisig: _deployment_payload, approve_hash_message, error = get_reuse_multisig_from_safe_payload( ledger_api=self.ledger_api, @@ -1150,7 +1151,10 @@ def get_deploy_data_from_safe( GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_CONTRACT.name ).contracts[self.chain_type] else: - raise NotImplementedError + deployment_payload = get_delployment_payload() + gnosis_safe_multisig = ContractConfigs.get( + GNOSIS_SAFE_PROXY_FACTORY_CONTRACT.name + ).contracts[self.chain_type] deploy_data = registry_instance.encodeABI( fn_name="deploy", @@ -1166,6 +1170,8 @@ def get_deploy_data_from_safe( "operation": MultiSendOperation.CALL, "value": 0, } + if approve_hash_message is None: + return [deploy_message] return [approve_hash_message, deploy_message] def get_terminate_data(self, service_id: int) -> t.Dict: From 5f1bfd943d62070531b6edf025bb6bcc8ab662bb Mon Sep 17 00:00:00 2001 From: Ardian Date: Wed, 14 Aug 2024 19:23:18 +0200 Subject: [PATCH 33/99] fix: allow single message --- operate/services/manage.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 235b0ce0a..4a92fa30a 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -667,12 +667,16 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to self.logger.info(f"{reuse_multisig=}") - approve_message, deploy_message = sftxb.get_deploy_data_from_safe( + messages = sftxb.get_deploy_data_from_safe( service_id=chain_data.token, reuse_multisig=reuse_multisig, master_safe=sftxb.wallet.safe, ) - sftxb.new_tx().add(approve_message).add(deploy_message).settle() + tx = sftxb.new_tx() + for message in messages: + tx.add(message) + tx.settle() + chain_data.on_chain_state = OnChainState.DEPLOYED service.store() From 4f406730e9122913d57f0d41f7e0ce56932884dc Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 15 Aug 2024 00:20:17 +0200 Subject: [PATCH 34/99] chore: minor fixes --- operate/services/manage.py | 39 +++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 4a92fa30a..7848baea7 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -364,6 +364,11 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too self, hash: str, ) -> None: + """ + Deploy as service on-chain + + :param hash: Service hash + """ service = self.load_or_create(hash=hash) for chain_id in service.chain_configs.keys(): self._deploy_service_onchain_from_safe( @@ -456,9 +461,14 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to and (on_chain_hash is not None) and (on_chain_hash != service.hash or current_agent_id != staking_params["agent_ids"][0]) ) + current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + self.logger.info(f"{current_staking_program=}") + self.logger.info(f"{user_params.staking_program_id=}") self.logger.info(f"{on_chain_hash=}") self.logger.info(f"{service.hash=}") + self.logger.info(f"{current_agent_id=}") + self.logger.info(f"{staking_params['agent_ids'][0]=}") self.logger.info(f"{is_first_mint=}") self.logger.info(f"{is_update=}") @@ -684,9 +694,9 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to info = sftxb.info(token_id=chain_data.token) chain_data.instances = info["instances"] chain_data.multisig = info["multisig"] - chain_data.staked = False chain_data.on_chain_state = OnChainState(info["service_state"]) service.store() + self.stake_service_on_chain_from_safe(hash=hash, chain_id=chain_id) def terminate_service_on_chain(self, hash: str) -> None: """ @@ -794,6 +804,9 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non ) # noqa: E800 def _get_current_staking_program(self, chain_data, ledger_config, sftxb) -> t.Optional[str]: + if chain_data.token == NON_EXISTENT_TOKEN: + return None + current_staking_program = None for staking_program in STAKING[ledger_config.chain]: state = sftxb.staking_status( @@ -839,7 +852,7 @@ def stake_service_on_chain(self, hash: str, chain_id: int, staking_program_id: s """ raise NotImplementedError - def stake_service_on_chain_from_safe(self, hash: str, chain_id: str, target_staking_program_id: str) -> None: + def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: """ Stake service on-chain @@ -850,8 +863,10 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str, target_stak service = self.load_or_create(hash=hash) chain_config = service.chain_configs[chain_id] ledger_config = chain_config.ledger_config - target_staking_contract = STAKING[ledger_config.chain][target_staking_program_id] chain_data = chain_config.chain_data + user_params = chain_data.user_params + target_staking_program_id = user_params.staking_program_id + target_staking_contract = STAKING[ledger_config.chain][target_staking_program_id] sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) # TODO fixme @@ -866,7 +881,7 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str, target_stak if is_staked: can_unstake = sftxb.can_unstake(chain_config.chain_data.token, current_staking_contract) if not chain_config.chain_data.user_params.use_staking and can_unstake: - self.logger.info("Use staking is set to false, but service is staked and can be unstaked. Unstaking...") + self.logger.info(f"Use staking is set to false, but service {chain_config.chain_data.token} is staked and can be unstaked. Unstaking...") self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) info = sftxb.info(token_id=chain_config.chain_data.token) @@ -877,21 +892,19 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str, target_stak ) if staking_state == StakingState.EVICTED and can_unstake: - self.logger.info(f"{chain_config.chain_data.token} has been evicted and can be unstaked. Unstaking...") + self.logger.info(f"Service {chain_config.chain_data.token} has been evicted and can be unstaked. Unstaking...") self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) if staking_state == StakingState.STAKED and can_unstake and not sftxb.staking_rewards_available(current_staking_contract): self.logger.info( - f"There are no rewards available, {chain_config.chain_data.token} " - f"is already staked and can be unstaked. " - f"Unstaking..." + f"There are no rewards available, service {chain_config.chain_data.token} " + f"is already staked and can be unstaked. Unstaking..." ) self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) if staking_state == StakingState.STAKED and current_staking_program != target_staking_contract and can_unstake: self.logger.info( - f"{chain_config.chain_data.token} is already staked in a different staking program. " - f"Unstaking..." + f"{chain_config.chain_data.token} is staked in a different staking program. Unstaking..." ) self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) @@ -1046,13 +1059,13 @@ def fund_service( # pylint: disable=too-many-arguments from_safe=from_safe, ) - safe_balanace = ledger_api.get_balance(chain_data.multisig) + safe_balance = ledger_api.get_balance(chain_data.multisig) safe_fund_treshold = ( safe_fund_treshold or chain_data.user_params.fund_requirements.safe ) - self.logger.info(f"Safe {chain_data.multisig} balance: {safe_balanace}") + self.logger.info(f"Safe {chain_data.multisig} balance: {safe_balance}") self.logger.info(f"Required balance: {safe_fund_treshold}") - if safe_balanace < safe_fund_treshold: + if safe_balance < safe_fund_treshold: self.logger.info("Funding safe") to_transfer = ( safe_topup or chain_data.user_params.fund_requirements.safe From 71d3d488394a0760dbb177d8bbecc7f2abf7deed Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 15 Aug 2024 01:18:57 +0200 Subject: [PATCH 35/99] chore: update --- operate/services/manage.py | 10 +++++++--- operate/services/protocol.py | 1 - operate/services/service.py | 2 -- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 7848baea7..04a2e942d 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -52,6 +52,7 @@ ServiceTemplate, LedgerConfig ) +from operate.utils.gnosis import NULL_ADDRESS from operate.wallet.master import MasterWalletManager @@ -70,7 +71,6 @@ HTTP_OK = 200 URI_HASH_POSITION = 7 IPFS_GATEWAY = "https://gateway.autonolas.tech/ipfs/" -ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" class ServiceManager: @@ -428,6 +428,10 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to if user_params.use_staking: self.logger.info("Checking staking compatibility") + + # TODO: Missing check when the service is currently staked in a program, but needs to be staked + # in a different target program. The In this case, balance = currently staked balance + safe balance + if chain_data.on_chain_state in ( OnChainState.NON_EXISTENT, OnChainState.PRE_REGISTRATION, @@ -672,7 +676,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to reuse_multisig = True info = sftxb.info(token_id=chain_data.token) - if info["multisig"] == "0x0000000000000000000000000000000000000000": + if info["multisig"] == NULL_ADDRESS: reuse_multisig = False self.logger.info(f"{reuse_multisig=}") @@ -1148,7 +1152,7 @@ def update_service( ) -> Service: """Update a service.""" - self.logger.info("-----Entering update service on-chain-----") + self.logger.info("-----Entering update local service-----") old_service = self.load_or_create( hash=old_hash, ) diff --git a/operate/services/protocol.py b/operate/services/protocol.py index 948a1776f..a7b3135fc 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -68,7 +68,6 @@ from operate.utils.gnosis import ( MultiSendOperation, SafeOperation, - get_owners, hash_payload_to_hex, skill_input_hex_to_payload, NULL_ADDRESS, ) diff --git a/operate/services/service.py b/operate/services/service.py index df00153fd..5ecabf103 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -69,8 +69,6 @@ ChainConfig, ChainConfigs, ChainType, - ConfigurationTemplate, - ConfigurationTemplates, DeployedNodes, DeploymentConfig, DeploymentStatus, From 515b7c2c49ff5e43af4fe6fbdb70349b7fa4c613 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 15 Aug 2024 01:50:33 +0200 Subject: [PATCH 36/99] chore: update --- operate/cli.py | 32 +++++++++----------------------- operate/services/manage.py | 20 ++++++++++---------- 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index 66b3d135c..fb4baa05d 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -510,44 +510,29 @@ async def _create_services(request: Request) -> JSONResponse: old_hash = manager.json[0]["hash"] if old_hash == template["hash"]: logger.info(f'Loading service {template["hash"]}') - chain_configs = [ - services.manage.ChainConfig.from_json(item) - for item in template["chain_configs"] - ] service = manager.load_or_create( hash=template["hash"], - chain_configs=chain_configs, + service_template=template, ) else: logger.info(f"Updating service from {old_hash} to " + template["hash"]) service = manager.update_service( old_hash=old_hash, new_hash=template["hash"], - rpc=template["configuration"]["rpc"], - on_chain_user_params=services.manage.OnChainUserParams.from_json( - template["configuration"] - ), - from_safe=True, + service_template=template, ) - update = True else: logger.info(f'Creating service {template["hash"]}') - chain_configs = [ - services.manage.ChainConfig.from_json(item) - for item in template["chain_configs"] - ] service = manager.load_or_create( hash=template["hash"], - chain_configs=chain_configs, + service_template=template, ) if template.get("deploy", False): def _fn() -> None: - manager.deploy_service_onchain_from_safe( - hash=service.hash, update=update - ) - manager.stake_service_on_chain_from_safe(hash=service.hash) + manager.deploy_service_onchain_from_safe(hash=service.hash) + # manager.stake_service_on_chain_from_safe(hash=service.hash) # Done inside deploy_service_onchain manager.fund_service(hash=service.hash) manager.deploy_service_locally(hash=service.hash) @@ -572,8 +557,8 @@ async def _update_services(request: Request) -> JSONResponse: ) if template.get("deploy", False): manager = operate.service_manager() - manager.deploy_service_onchain_from_safe(hash=service.hash, update=True) - manager.stake_service_on_chain_from_safe(hash=service.hash) + manager.deploy_service_onchain_from_safe(hash=service.hash) + # manager.stake_service_on_chain_from_safe(hash=service.hash) # Done in deploy_service_onchain_from_safe manager.fund_service(hash=service.hash) manager.deploy_service_locally(hash=service.hash) schedule_funding_job(service=service.hash) @@ -597,6 +582,7 @@ async def _get_service(request: Request) -> JSONResponse: ) ) + # TODO this endpoint is possibly not used @app.post("/api/services/{service}/onchain/deploy") @with_retries async def _deploy_service_onchain(request: Request) -> JSONResponse: @@ -689,7 +675,7 @@ async def _start_service_locally(request: Request) -> JSONResponse: def _fn() -> None: manager.deploy_service_onchain(hash=service) - manager.stake_service_on_chain(hash=service) + # manager.stake_service_on_chain(hash=service) manager.fund_service(hash=service) manager.deploy_service_locally(hash=service, force=True) diff --git a/operate/services/manage.py b/operate/services/manage.py index 04a2e942d..f9bf676d9 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -402,6 +402,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc os.environ["OPEN_AUTONOMY_SUBGRAPH_URL"] = "https://subgraph.autonolas.tech/subgraphs/name/autonolas-staging" + current_agent_id = None if chain_data.token > -1: self.logger.info("Syncing service state") info = sftxb.info(token_id=chain_data.token) @@ -1146,26 +1147,25 @@ def update_service( self, old_hash: str, new_hash: str, - rpc: t.Optional[str] = None, - on_chain_user_params: t.Optional[OnChainUserParams] = None, - from_safe: bool = True, # pylint: disable=unused-argument + service_template: t.Optional[ServiceTemplate] = None, ) -> Service: """Update a service.""" self.logger.info("-----Entering update local service-----") old_service = self.load_or_create( - hash=old_hash, + hash=old_hash ) new_service = self.load_or_create( hash=new_hash, - rpc=rpc or old_service.ledger_config.rpc, - on_chain_user_params=on_chain_user_params - or old_service.chain_data.user_params, + service_template=service_template ) new_service.keys = old_service.keys - new_service.chain_data = old_service.chain_data - new_service.ledger_config = old_service.ledger_config - new_service.chain_data.on_chain_state = OnChainState.NON_EXISTENT + # new_Service.home_chain_id = old_service.home_chain_id + + # FIXME New service must copy all chain_data from old service, + # but if service_template is not None, it must copy the user_params + # passed in the service_template. + new_service.chain_configs = old_service.chain_configs new_service.store() # The following logging has been added to identify OS issues when From 3b2ea44e73214f2517f65f1ef77ce51432aa533d Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 15 Aug 2024 02:14:53 +0200 Subject: [PATCH 37/99] chore: update --- operate/cli.py | 1 - operate/services/manage.py | 12 +++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index fb4baa05d..86acd8031 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -505,7 +505,6 @@ async def _create_services(request: Request) -> JSONResponse: return USER_NOT_LOGGED_IN_ERROR template = await request.json() manager = operate.service_manager() - update = False if len(manager.json) > 0: old_hash = manager.json[0]["hash"] if old_hash == template["hash"]: diff --git a/operate/services/manage.py b/operate/services/manage.py index f9bf676d9..aa9081600 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -1162,10 +1162,16 @@ def update_service( new_service.keys = old_service.keys # new_Service.home_chain_id = old_service.home_chain_id - # FIXME New service must copy all chain_data from old service, + # TODO - Ensure this works as expected - New service must copy all chain_data from old service, # but if service_template is not None, it must copy the user_params - # passed in the service_template. - new_service.chain_configs = old_service.chain_configs + # passed in the service_template and copy the remaining attributes from old_service. + + new_service.chain_configs = {} + for chain_id, config in old_service.chain_configs.items(): + new_service.chain_configs[chain_id] = config + if service_template: + new_service.chain_configs[chain_id].chain_data.user_params = OnChainUserParams.from_json(service_template["configurations"][chain_id]) + new_service.store() # The following logging has been added to identify OS issues when From d2948670340b09f301c659c7d9a5ba75d2e61840 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 15 Aug 2024 17:54:07 +0100 Subject: [PATCH 38/99] refactor: remove minimumFunding property from GNOSIS chain constant --- frontend/constants/chains.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/constants/chains.ts b/frontend/constants/chains.ts index 5c944b011..d77784665 100644 --- a/frontend/constants/chains.ts +++ b/frontend/constants/chains.ts @@ -2,8 +2,7 @@ export const CHAINS: { [chain: string]: { currency: string; chainId: number; - minimumFunding: number; }; } = { - gnosis: { currency: 'XDAI', chainId: 100, minimumFunding: 1 }, + GNOSIS: { currency: 'XDAI', chainId: 100 }, }; From 02cd87f0a96a8346b7242d229b9cd96dcce2b3b5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 15 Aug 2024 17:55:15 +0100 Subject: [PATCH 39/99] update types --- frontend/client/types.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index a3613aa7d..ac244afd3 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -48,7 +48,8 @@ export type ConfigurationTemplate = { agent_id: number; threshold: number; use_staking: boolean; - cost_of_bond: number; + cost_of_bond: number; // TODO: REQUEST RESET TO NAMING CONVENTION, OLAS_COST_OF_BOND + olas_required_to_stake: number; // TODO: CLARIFY WHY THIS WAS REMOVED monthly_gas_estimate: number; fund_requirements: FundRequirementsTemplate; }; From 52e6346271dcf445204d8db9458cac4c2f59e670 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 15 Aug 2024 17:56:05 +0100 Subject: [PATCH 40/99] refactor: gnosis chain id and variable rename --- frontend/components/MainPage/header/constants.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/frontend/components/MainPage/header/constants.ts b/frontend/components/MainPage/header/constants.ts index 87083563d..a9e9a098a 100644 --- a/frontend/components/MainPage/header/constants.ts +++ b/frontend/components/MainPage/header/constants.ts @@ -1,20 +1,27 @@ import { formatUnits } from 'ethers/lib/utils'; +import { CHAINS } from '@/constants/chains'; import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; // TODO: Move this to more appropriate location (root /constants) - const olasCostOfBond = Number( - formatUnits(`${SERVICE_TEMPLATES[0].configuration.olas_cost_of_bond}`, 18), + formatUnits( + `${SERVICE_TEMPLATES[0].configurations[CHAINS.GNOSIS.chainId].cost_of_bond}`, + 18, + ), ); + const olasRequiredToStake = Number( formatUnits( - `${SERVICE_TEMPLATES[0].configuration.olas_required_to_stake}`, + `${SERVICE_TEMPLATES[0].configurations[CHAINS.GNOSIS.chainId].olas_required_to_stake}`, 18, ), ); export const requiredOlas = olasCostOfBond + olasRequiredToStake; export const requiredGas = Number( - formatUnits(`${SERVICE_TEMPLATES[0].configuration.monthly_gas_estimate}`, 18), + formatUnits( + `${SERVICE_TEMPLATES[0].configurations[CHAINS.GNOSIS.chainId].monthly_gas_estimate}`, + 18, + ), ); From 9a26d8de22e78a9d1a45cfec71f506a38b217c69 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 15 Aug 2024 17:56:14 +0100 Subject: [PATCH 41/99] feat: update olas_required_to_stake in service templates --- frontend/constants/serviceTemplates.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 75219bcb9..32fb9b435 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -16,12 +16,13 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ threshold: 1, use_staking: true, cost_of_bond: 10000000000000000, + olas_required_to_stake: 10000000000000000000, monthly_gas_estimate: 10000000000000000000, fund_requirements: { agent: 100000000000000000, safe: 5000000000000000000, }, - } + }, }, }, ]; From 2428802fb5be649abcc34bb5e335ba9fb5e1aff1 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 15 Aug 2024 18:00:43 +0100 Subject: [PATCH 42/99] refactor: service template reference refactors --- .../MainPage/sections/NeedsFundsSection.tsx | 6 +++++- frontend/hooks/useServices.ts | 7 +++++-- frontend/utils/service.ts | 11 +++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/frontend/components/MainPage/sections/NeedsFundsSection.tsx b/frontend/components/MainPage/sections/NeedsFundsSection.tsx index 480b533c9..0bfba6e60 100644 --- a/frontend/components/MainPage/sections/NeedsFundsSection.tsx +++ b/frontend/components/MainPage/sections/NeedsFundsSection.tsx @@ -2,6 +2,7 @@ import { Flex, Typography } from 'antd'; import { formatUnits } from 'ethers/lib/utils'; import { ReactNode, useEffect, useMemo } from 'react'; +import { CHAINS } from '@/constants/chains'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; @@ -31,7 +32,10 @@ const useNeedsFunds = () => { const serviceFundRequirements = useMemo(() => { const monthlyGasEstimate = Number( - formatUnits(`${serviceTemplate.configuration.monthly_gas_estimate}`, 18), + formatUnits( + `${serviceTemplate.configurations[CHAINS.GNOSIS.chainId].monthly_gas_estimate}`, + 18, + ), ); const minimumStakedAmountRequired = diff --git a/frontend/hooks/useServices.ts b/frontend/hooks/useServices.ts index 2de306fcb..595dca84c 100644 --- a/frontend/hooks/useServices.ts +++ b/frontend/hooks/useServices.ts @@ -1,6 +1,7 @@ import { useContext } from 'react'; import { Service, ServiceHash, ServiceTemplate } from '@/client'; +import { CHAINS } from '@/constants/chains'; import { ServicesContext } from '@/context/ServicesProvider'; import MulticallService from '@/service/Multicall'; import { ServicesService } from '@/service/Services'; @@ -28,9 +29,11 @@ const checkServiceIsFunded = async ( Object.assign(acc, { [address]: instances.includes(address) ? balances[address] > - serviceTemplate.configuration.fund_requirements.agent + serviceTemplate.configurations[CHAINS.GNOSIS.chainId] + .fund_requirements.agent : balances[address] > - serviceTemplate.configuration.fund_requirements.safe, + serviceTemplate.configurations[CHAINS.GNOSIS.chainId] + .fund_requirements.safe, }), {}, ); diff --git a/frontend/utils/service.ts b/frontend/utils/service.ts index 160a9fee5..b03820ff2 100644 --- a/frontend/utils/service.ts +++ b/frontend/utils/service.ts @@ -1,15 +1,22 @@ import { formatUnits } from 'ethers/lib/utils'; import { ServiceTemplate } from '@/client'; +import { CHAINS } from '@/constants/chains'; export const getMinimumStakedAmountRequired = ( serviceTemplate: ServiceTemplate, ) => { const olasCostOfBond = Number( - formatUnits(`${serviceTemplate.configuration.olas_cost_of_bond}`, 18), + formatUnits( + `${serviceTemplate.configurations[CHAINS.GNOSIS.chainId].cost_of_bond}`, + 18, + ), ); const olasRequiredToStake = Number( - formatUnits(`${serviceTemplate.configuration.olas_required_to_stake}`, 18), + formatUnits( + `${serviceTemplate.configurations[CHAINS.GNOSIS.chainId].olas_required_to_stake}`, + 18, + ), ); return olasCostOfBond + olasRequiredToStake; From 316269ad192579cbecd94d801c41677b65e4b1b5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 15 Aug 2024 19:18:43 +0100 Subject: [PATCH 43/99] refactor: staking program alert notification section --- frontend/components/MainPage/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index 2c833cf7d..54fc9c57d 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -12,6 +12,7 @@ import { AddFundsSection } from './sections/AddFundsSection'; import { GasBalanceSection } from './sections/GasBalanceSection'; import { KeepAgentRunningSection } from './sections/KeepAgentRunningSection'; import { MainNeedsFunds } from './sections/NeedsFundsSection'; +import { NewStakingProgramAlertSection } from './sections/NewStakingProgramAlertSection'; import { MainOlasBalance } from './sections/OlasBalanceSection'; import { MainRewards } from './sections/RewardsSection'; @@ -49,6 +50,7 @@ export const Main = () => { style={{ borderTopColor: 'transparent' }} > + From 9df9871b8c65f8a8858a90d5fa421c0e018dfe6e Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 15 Aug 2024 19:18:57 +0100 Subject: [PATCH 44/99] chore: delete unused --- .../sections/NewIncentiveAlertSection.tsx | 35 ------------------- 1 file changed, 35 deletions(-) delete mode 100644 frontend/components/MainPage/sections/NewIncentiveAlertSection.tsx diff --git a/frontend/components/MainPage/sections/NewIncentiveAlertSection.tsx b/frontend/components/MainPage/sections/NewIncentiveAlertSection.tsx deleted file mode 100644 index b99c4f1a6..000000000 --- a/frontend/components/MainPage/sections/NewIncentiveAlertSection.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Button, Flex, Typography } from 'antd'; - -import { Pages } from '@/enums/PageState'; -import { usePageState } from '@/hooks/usePageState'; - -import { CustomAlert } from '../../Alert'; -import { CardSection } from '../../styled/CardSection'; - -const { Text } = Typography; - -export const NewIncentiveAlert = () => { - const { goto } = usePageState(); - - return ( - - - A new incentive program is available for your agent! - - - } - /> - - ); -}; From feda9749702c3703ec1669cffdbc3e0ed7136f6e Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 15 Aug 2024 19:19:08 +0100 Subject: [PATCH 45/99] feat: new staking program alert section --- .../NewStakingProgramAlertSection.tsx | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 frontend/components/MainPage/sections/NewStakingProgramAlertSection.tsx diff --git a/frontend/components/MainPage/sections/NewStakingProgramAlertSection.tsx b/frontend/components/MainPage/sections/NewStakingProgramAlertSection.tsx new file mode 100644 index 000000000..bce9d0983 --- /dev/null +++ b/frontend/components/MainPage/sections/NewStakingProgramAlertSection.tsx @@ -0,0 +1,36 @@ +import { Button, Flex, Typography } from 'antd'; + +import { Pages } from '@/enums/PageState'; +import { usePageState } from '@/hooks/usePageState'; + +import { CustomAlert } from '../../Alert'; +import { CardSection } from '../../styled/CardSection'; + +const { Text } = Typography; + +export const NewStakingProgramAlertSection = () => { + const { goto } = usePageState(); + + return ( + + + A new staking contract is available for your agent! + + + } + /> + + ); +}; From 8e1a9c44624e35ad78159ef0d40f1fc3300b404f Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 15 Aug 2024 19:19:25 +0100 Subject: [PATCH 46/99] feat: add staking programs enums and records --- frontend/constants/contractAddresses.ts | 8 ++++++-- frontend/enums/StakingPrograms.ts | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 frontend/enums/StakingPrograms.ts diff --git a/frontend/constants/contractAddresses.ts b/frontend/constants/contractAddresses.ts index 823e9710b..95d33c6fa 100644 --- a/frontend/constants/contractAddresses.ts +++ b/frontend/constants/contractAddresses.ts @@ -1,4 +1,5 @@ import { Chain } from '@/client'; +import { StakingProgram } from '@/enums/StakingPrograms'; import { Address } from '@/types/Address'; export const MULTICALL_CONTRACT_ADDRESS: Address = @@ -17,9 +18,12 @@ export const SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT_ADDRESS: Record< export const SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESS: Record< number, - Address + Record > = { - [Chain.GNOSIS]: '0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A', + [Chain.GNOSIS]: { + [StakingProgram.Alpha]: '0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A', + [StakingProgram.Beta]: '0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d', + }, }; export const AGENT_MECH_CONTRACT_ADDRESS: Record = { diff --git a/frontend/enums/StakingPrograms.ts b/frontend/enums/StakingPrograms.ts new file mode 100644 index 000000000..c3d98cd42 --- /dev/null +++ b/frontend/enums/StakingPrograms.ts @@ -0,0 +1,4 @@ +export enum StakingProgram { + Alpha = 'pearl_alpha', + Beta = 'pearl_beta', +} From 305526dbe9fa39ba45b558f92d1d8a87ba0bd633 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 15 Aug 2024 19:26:58 +0100 Subject: [PATCH 47/99] refactor: remove and rename irrelevant mocking --- .../StakingContract/StakingContractTag.tsx | 10 ++++------ .../ManageStakingPage/StakingContract/index.tsx | 17 +++++------------ frontend/components/ManageStakingPage/index.tsx | 10 +++++----- frontend/constants/contractAddresses.ts | 2 +- frontend/enums/IcentiveProgram.ts | 5 ----- .../{StakingPrograms.ts => StakingProgram.ts} | 0 frontend/enums/StakingProgramStatus.ts | 4 ++++ frontend/hooks/useStakingProgram.ts | 8 ++++---- frontend/types/IncentiveProgram.ts | 12 ------------ frontend/types/StakingProgram.ts | 12 ++++++++++++ 10 files changed, 35 insertions(+), 45 deletions(-) delete mode 100644 frontend/enums/IcentiveProgram.ts rename frontend/enums/{StakingPrograms.ts => StakingProgram.ts} (100%) create mode 100644 frontend/enums/StakingProgramStatus.ts delete mode 100644 frontend/types/IncentiveProgram.ts create mode 100644 frontend/types/StakingProgram.ts diff --git a/frontend/components/ManageStakingPage/StakingContract/StakingContractTag.tsx b/frontend/components/ManageStakingPage/StakingContract/StakingContractTag.tsx index 9233845fa..857dd4f56 100644 --- a/frontend/components/ManageStakingPage/StakingContract/StakingContractTag.tsx +++ b/frontend/components/ManageStakingPage/StakingContract/StakingContractTag.tsx @@ -1,18 +1,16 @@ import { Tag } from 'antd'; -import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; +import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; export const StakingContractTag = ({ status, }: { - status: IncentiveProgramStatus; + status: StakingProgramStatus; }) => { - if (status === IncentiveProgramStatus.New) { + if (status === StakingProgramStatus.New) { return New; - } else if (status === IncentiveProgramStatus.Selected) { + } else if (status === StakingProgramStatus.Selected) { return Selected; - } else if (status === IncentiveProgramStatus.Deprecated) { - return Deprecated; } return null; }; diff --git a/frontend/components/ManageStakingPage/StakingContract/index.tsx b/frontend/components/ManageStakingPage/StakingContract/index.tsx index 639835220..d7c2762d8 100644 --- a/frontend/components/ManageStakingPage/StakingContract/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContract/index.tsx @@ -4,9 +4,9 @@ import styled from 'styled-components'; import { CardSection } from '@/components/styled/CardSection'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; +import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; import { useBalance } from '@/hooks/useBalance'; -import { IncentiveProgram } from '@/types/IncentiveProgram'; +import { StakingProgram } from '@/types/StakingProgram'; import { AlertInsufficientMigrationFunds, @@ -40,16 +40,11 @@ const ContractParameter = ({ ); -export const StakingContract = ({ - contract, -}: { - contract: IncentiveProgram; -}) => { +export const StakingContract = ({ contract }: { contract: StakingProgram }) => { const { token } = useToken(); const { totalOlasBalance, isBalanceLoaded } = useBalance(); - const isDeprecated = contract.status === IncentiveProgramStatus.Deprecated; - const isSelected = contract.status === IncentiveProgramStatus.Selected; + const isSelected = contract.status === StakingProgramStatus.Selected; const isEnoughOlas = useMemo(() => { if (totalOlasBalance === undefined) return false; @@ -58,7 +53,6 @@ export const StakingContract = ({ const isAppVersionCompatible = true; // contract.appVersion === 'rc105'; const isMigratable = - !isDeprecated && !isSelected && isBalanceLoaded && contract.isEnoughSlots && @@ -66,7 +60,7 @@ export const StakingContract = ({ isAppVersionCompatible; const cantMigrateAlert = useMemo(() => { - if (isDeprecated || isSelected || !isBalanceLoaded) { + if (isSelected || !isBalanceLoaded) { return null; } @@ -84,7 +78,6 @@ export const StakingContract = ({ return ; } }, [ - isDeprecated, isSelected, isBalanceLoaded, totalOlasBalance, diff --git a/frontend/components/ManageStakingPage/index.tsx b/frontend/components/ManageStakingPage/index.tsx index 364def9cb..9650564de 100644 --- a/frontend/components/ManageStakingPage/index.tsx +++ b/frontend/components/ManageStakingPage/index.tsx @@ -1,22 +1,22 @@ import { CloseOutlined } from '@ant-design/icons'; import { Button, Card } from 'antd'; -import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; import { Pages } from '@/enums/PageState'; +import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; import { usePageState } from '@/hooks/usePageState'; -import { IncentiveProgram } from '@/types/IncentiveProgram'; +import { StakingProgram } from '@/types/StakingProgram'; import { CardTitle } from '../Card/CardTitle'; import { StakingContract } from './StakingContract'; import { WhatAreStakingContractsSection } from './WhatAreStakingContracts'; -const mockStakingContracts: IncentiveProgram[] = [ +const mockStakingContracts: StakingProgram[] = [ { name: 'Pearl Beta', rewardsPerWorkPeriod: 0.14, requiredOlasForStaking: 40, isEnoughSlots: true, - status: IncentiveProgramStatus.New, + status: StakingProgramStatus.New, contractAddress: '0x1234567890', }, { @@ -24,7 +24,7 @@ const mockStakingContracts: IncentiveProgram[] = [ rewardsPerWorkPeriod: 0.047, requiredOlasForStaking: 20, isEnoughSlots: true, - status: IncentiveProgramStatus.Selected, + status: StakingProgramStatus.Selected, contractAddress: '0x0987654321', }, ]; diff --git a/frontend/constants/contractAddresses.ts b/frontend/constants/contractAddresses.ts index 95d33c6fa..4969f5715 100644 --- a/frontend/constants/contractAddresses.ts +++ b/frontend/constants/contractAddresses.ts @@ -1,5 +1,5 @@ import { Chain } from '@/client'; -import { StakingProgram } from '@/enums/StakingPrograms'; +import { StakingProgram } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; export const MULTICALL_CONTRACT_ADDRESS: Address = diff --git a/frontend/enums/IcentiveProgram.ts b/frontend/enums/IcentiveProgram.ts deleted file mode 100644 index f0351765a..000000000 --- a/frontend/enums/IcentiveProgram.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum IncentiveProgramStatus { - New = 'new', - Selected = 'current', - Deprecated = 'deprecated', -} diff --git a/frontend/enums/StakingPrograms.ts b/frontend/enums/StakingProgram.ts similarity index 100% rename from frontend/enums/StakingPrograms.ts rename to frontend/enums/StakingProgram.ts diff --git a/frontend/enums/StakingProgramStatus.ts b/frontend/enums/StakingProgramStatus.ts new file mode 100644 index 000000000..d2789f1ef --- /dev/null +++ b/frontend/enums/StakingProgramStatus.ts @@ -0,0 +1,4 @@ +export enum StakingProgramStatus { + New = 'new', + Selected = 'current', +} diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index fc82e458f..eca089948 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -1,7 +1,7 @@ import { useState } from 'react'; -import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; -import { IncentiveProgram } from '@/types/IncentiveProgram'; +import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; +import { StakingProgram } from '@/types/StakingProgram'; /** * Mock hook for staking program abstraction @@ -12,9 +12,9 @@ export const useStakingProgram = () => { // TODO: Calculate current staking program // from current staking contract address - const currentStakingProgram: IncentiveProgram = { + const currentStakingProgram: StakingProgram = { name: 'Pearl Alpha', - status: IncentiveProgramStatus.Selected, + status: StakingProgramStatus.Selected, contractAddress: '0x', rewardsPerWorkPeriod: 0.25, requiredOlasForStaking: 20, diff --git a/frontend/types/IncentiveProgram.ts b/frontend/types/IncentiveProgram.ts deleted file mode 100644 index e3d4a6c7a..000000000 --- a/frontend/types/IncentiveProgram.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { IncentiveProgramStatus } from '@/enums/IcentiveProgram'; - -import { Address } from './Address'; - -export type IncentiveProgram = { - name: string; - rewardsPerWorkPeriod: number; - requiredOlasForStaking: number; - isEnoughSlots: boolean; - status: IncentiveProgramStatus; - contractAddress: Address; -}; diff --git a/frontend/types/StakingProgram.ts b/frontend/types/StakingProgram.ts new file mode 100644 index 000000000..77d551d18 --- /dev/null +++ b/frontend/types/StakingProgram.ts @@ -0,0 +1,12 @@ +import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; + +import { Address } from './Address'; + +export type StakingProgram = { + name: string; + rewardsPerWorkPeriod: number; + requiredOlasForStaking: number; + isEnoughSlots?: boolean; + status: StakingProgramStatus; + contractAddress: Address; +}; From 8174bc7f4956f56bed6766f601d3990a24e1089f Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 10:11:51 +0100 Subject: [PATCH 48/99] refactor: logging for electron store and IPC stuff --- electron/main.js | 28 ++++++++++++------------ electron/store.js | 54 +++++++++++++++++++++++++++++------------------ 2 files changed, 48 insertions(+), 34 deletions(-) diff --git a/electron/main.js b/electron/main.js index 5a01cae73..e60d56fd1 100644 --- a/electron/main.js +++ b/electron/main.js @@ -195,7 +195,7 @@ const HEIGHT = 700; /** * Creates the main window */ -const createMainWindow = () => { +const createMainWindow = async () => { const width = isDev ? 840 : APP_WIDTH; mainWindow = new BrowserWindow({ title: 'Pearl', @@ -216,12 +216,6 @@ const createMainWindow = () => { mainWindow.setMenuBarVisibility(true); - if (isDev) { - mainWindow.loadURL(`http://localhost:${appConfig.ports.dev.next}`); - } else { - mainWindow.loadURL(`http://localhost:${appConfig.ports.prod.next}`); - } - ipcMain.on('close-app', () => { mainWindow.close(); }); @@ -264,15 +258,23 @@ const createMainWindow = () => { event.preventDefault(); mainWindow.hide(); }); - - const storeInitialValues = { - environmentName: process.env.IS_STAGING ? 'staging' : '', - }; - setupStoreIpc(ipcMain, mainWindow, storeInitialValues); + + try { + logger.electron('Setting up store IPC'); + await setupStoreIpc(ipcMain, mainWindow); + } catch (e) { + logger.electron('Store IPC failed:', JSON.stringify(e)); + } if (isDev) { mainWindow.webContents.openDevTools(); } + + if (isDev) { + mainWindow.loadURL(`http://localhost:${appConfig.ports.dev.next}`); + } else { + mainWindow.loadURL(`http://localhost:${appConfig.ports.prod.next}`); + } }; async function launchDaemon() { @@ -494,7 +496,7 @@ ipcMain.on('check', async function (event, _argument) { } event.sender.send('response', 'Launching App'); - createMainWindow(); + await createMainWindow(); createTray(); splashWindow.destroy(); } catch (e) { diff --git a/electron/store.js b/electron/store.js index afbc7f62d..fc2f09d7e 100644 --- a/electron/store.js +++ b/electron/store.js @@ -1,24 +1,36 @@ +// @ts-check +const { logger } = require('./logger'); + // set schema to validate store data -const defaultSchema = { - environmentName: { type: 'string', default: '' }, - isInitialFunded: { type: 'boolean', default: false }, - firstStakingRewardAchieved: { type: 'boolean', default: false }, - firstRewardNotificationShown: { type: 'boolean', default: false }, - agentEvictionAlertShown: { type: 'boolean', default: false }, +const schema = { + isInitialFunded: { type: 'boolean', default: null }, // TODO: reconsider this default, can be problematic if user has already funded prior to implementation + firstStakingRewardAchieved: { type: 'boolean', default: null }, + firstRewardNotificationShown: { type: 'boolean', default: null }, + agentEvictionAlertShown: { type: 'boolean', default: null }, + + environmentName: { type: 'string', default: null }, + currentStakingProgram: { type: 'string', default: null }, }; -const setupStoreIpc = async (ipcChannel, mainWindow, storeInitialValues) => { - const Store = (await import('electron-store')).default; +/** + * Sets up the IPC communication and initializes the Electron store with default values and schema. + * @param {Electron.IpcMain} ipcMain - The IPC channel for communication. + * @param {Electron.BrowserWindow} mainWindow - The main Electron browser window. + * @returns {Promise} - A promise that resolves once the store is set up. + */ +const setupStoreIpc = async (ipcMain, mainWindow) => { + let Store; + try { + Store = await (import('electron-store').then((mod) => mod.default)); + } catch (error) { + logger.error(`Error importing electron-store: ${error}`); + } - // set default values for store - const schema = Object.assign({}, defaultSchema); - Object.keys(schema).forEach((key) => { - if (storeInitialValues[key] !== undefined) { - schema[key].default = storeInitialValues[key]; - } - }); + if (!Store) { + logger.error('electron-store not found'); + return; + } - /** @type import Store from 'electron-store' */ const store = new Store({ schema }); store.onDidAnyChange((data) => { @@ -27,11 +39,11 @@ const setupStoreIpc = async (ipcChannel, mainWindow, storeInitialValues) => { }); // exposed to electron browser window - ipcChannel.handle('store', () => store.store); - ipcChannel.handle('store-get', (_, key) => store.get(key)); - ipcChannel.handle('store-set', (_, key, value) => store.set(key, value)); - ipcChannel.handle('store-delete', (_, key) => store.delete(key)); - ipcChannel.handle('store-clear', (_) => store.clear()); + ipcMain.handle('store', () => store.store); + ipcMain.handle('store-get', (_, key) => store.get(key)); + ipcMain.handle('store-set', (_, key, value) => store.set(key, value)); + ipcMain.handle('store-delete', (_, key) => store.delete(key)); + ipcMain.handle('store-clear', (_) => store.clear()); }; module.exports = { setupStoreIpc }; From bea906132942f2d6a109723027ecbbe3dadcc3d1 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Fri, 16 Aug 2024 14:02:42 +0300 Subject: [PATCH 49/99] fix: electron-store issue --- electron/store.js | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/electron/store.js b/electron/store.js index fc2f09d7e..b8c5c9093 100644 --- a/electron/store.js +++ b/electron/store.js @@ -1,15 +1,12 @@ -// @ts-check -const { logger } = require('./logger'); - // set schema to validate store data const schema = { - isInitialFunded: { type: 'boolean', default: null }, // TODO: reconsider this default, can be problematic if user has already funded prior to implementation - firstStakingRewardAchieved: { type: 'boolean', default: null }, - firstRewardNotificationShown: { type: 'boolean', default: null }, - agentEvictionAlertShown: { type: 'boolean', default: null }, + isInitialFunded: { type: 'boolean', default: false }, // TODO: reconsider this default, can be problematic if user has already funded prior to implementation + firstStakingRewardAchieved: { type: 'boolean', default: false }, + firstRewardNotificationShown: { type: 'boolean', default: false }, + agentEvictionAlertShown: { type: 'boolean', default: false }, - environmentName: { type: 'string', default: null }, - currentStakingProgram: { type: 'string', default: null }, + environmentName: { type: 'string', default: '' }, + currentStakingProgram: { type: 'string', default: '' }, }; /** @@ -19,17 +16,7 @@ const schema = { * @returns {Promise} - A promise that resolves once the store is set up. */ const setupStoreIpc = async (ipcMain, mainWindow) => { - let Store; - try { - Store = await (import('electron-store').then((mod) => mod.default)); - } catch (error) { - logger.error(`Error importing electron-store: ${error}`); - } - - if (!Store) { - logger.error('electron-store not found'); - return; - } + const Store = (await import("electron-store")).default; const store = new Store({ schema }); From 6cafa985c5126348885974fbca95dadd82dff9b1 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:09:16 +0100 Subject: [PATCH 50/99] chore: add minStakingDeposit for n+1 calculation --- frontend/types/Autonolas.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/types/Autonolas.ts b/frontend/types/Autonolas.ts index f971ace82..3cd552d1c 100644 --- a/frontend/types/Autonolas.ts +++ b/frontend/types/Autonolas.ts @@ -20,4 +20,6 @@ export type StakingContractInfo = { serviceStakingStartTime: number; /** 0: not staked, 1: staked, 2: unstaked - current state of the service */ serviceStakingState: number; + /** OLAS cost of staking */ + minStakingDeposit: number; }; From 300d18e4f5653e5c320b401858c49bfd1440510c Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:09:51 +0100 Subject: [PATCH 51/99] refactor: multi staking program refactor to Autonolas service --- frontend/service/Autonolas.ts | 151 ++++++++++++++++++++++++++++------ 1 file changed, 125 insertions(+), 26 deletions(-) diff --git a/frontend/service/Autonolas.ts b/frontend/service/Autonolas.ts index 0598210e4..190fc6030 100644 --- a/frontend/service/Autonolas.ts +++ b/frontend/service/Autonolas.ts @@ -12,10 +12,11 @@ import { MECH_ACTIVITY_CHECKER_CONTRACT_ADDRESS, SERVICE_REGISTRY_L2_CONTRACT_ADDRESS, SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT_ADDRESS, - SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESS, + SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES, } from '@/constants/contractAddresses'; import { gnosisMulticallProvider } from '@/constants/providers'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; +import { StakingProgram } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; import { StakingContractInfo, StakingRewardsInfo } from '@/types/Autonolas'; @@ -26,10 +27,27 @@ const agentMechContract = new MulticallContract( AGENT_MECH_ABI.filter((abi) => abi.type === 'function'), // weird bug in the package where their filter doesn't work.. ); -const serviceStakingTokenMechUsageContract = new MulticallContract( - SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESS[Chain.GNOSIS], - SERVICE_STAKING_TOKEN_MECH_USAGE_ABI.filter((abi) => abi.type === 'function'), // same as above -); +const serviceStakingTokenMechUsageContracts: Record< + StakingProgram, + MulticallContract +> = { + [StakingProgram.Alpha]: new MulticallContract( + SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS][ + StakingProgram.Alpha + ], + SERVICE_STAKING_TOKEN_MECH_USAGE_ABI.filter( + (abi) => abi.type === 'function', + ), // same as above + ), + [StakingProgram.Beta]: new MulticallContract( + SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS][ + StakingProgram.Beta + ], + SERVICE_STAKING_TOKEN_MECH_USAGE_ABI.filter( + (abi) => abi.type === 'function', + ), // same as above + ), +}; const serviceRegistryTokenUtilityContract = new MulticallContract( SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT_ADDRESS[Chain.GNOSIS], @@ -49,22 +67,28 @@ const mechActivityCheckerContract = new MulticallContract( const getAgentStakingRewardsInfo = async ({ agentMultisigAddress, serviceId, + stakingProgram, }: { agentMultisigAddress: Address; serviceId: number; + stakingProgram: StakingProgram; }): Promise => { if (!agentMultisigAddress) return; if (!serviceId) return; const contractCalls = [ agentMechContract.getRequestsCount(agentMultisigAddress), - serviceStakingTokenMechUsageContract.getServiceInfo(serviceId), - serviceStakingTokenMechUsageContract.livenessPeriod(), + serviceStakingTokenMechUsageContracts[stakingProgram].getServiceInfo( + serviceId, + ), + serviceStakingTokenMechUsageContracts[stakingProgram].livenessPeriod(), mechActivityCheckerContract.livenessRatio(), - serviceStakingTokenMechUsageContract.rewardsPerSecond(), - serviceStakingTokenMechUsageContract.calculateStakingReward(serviceId), - serviceStakingTokenMechUsageContract.minStakingDeposit(), - serviceStakingTokenMechUsageContract.tsCheckpoint(), + serviceStakingTokenMechUsageContracts[stakingProgram].rewardsPerSecond(), + serviceStakingTokenMechUsageContracts[ + stakingProgram + ].calculateStakingReward(serviceId), + serviceStakingTokenMechUsageContracts[stakingProgram].minStakingDeposit(), + serviceStakingTokenMechUsageContracts[stakingProgram].tsCheckpoint(), ]; await gnosisMulticallProvider.init(); @@ -136,11 +160,13 @@ const getAgentStakingRewardsInfo = async ({ } as StakingRewardsInfo; }; -const getAvailableRewardsForEpoch = async (): Promise => { +const getAvailableRewardsForEpoch = async ( + stakingProgram: StakingProgram, +): Promise => { const contractCalls = [ - serviceStakingTokenMechUsageContract.rewardsPerSecond(), - serviceStakingTokenMechUsageContract.livenessPeriod(), // epoch length - serviceStakingTokenMechUsageContract.tsCheckpoint(), // last checkpoint timestamp + serviceStakingTokenMechUsageContracts[stakingProgram].rewardsPerSecond(), + serviceStakingTokenMechUsageContracts[stakingProgram].livenessPeriod(), // epoch length + serviceStakingTokenMechUsageContracts[stakingProgram].tsCheckpoint(), // last checkpoint timestamp ]; await gnosisMulticallProvider.init(); @@ -157,21 +183,24 @@ const getAvailableRewardsForEpoch = async (): Promise => { ); }; -/** - * function to get the staking contract info - */ -const getStakingContractInfo = async ( +const getStakingContractInfoByServiceIdStakingProgram = async ( serviceId: number, + stakingProgram: StakingProgram, ): Promise => { if (!serviceId) return; const contractCalls = [ - serviceStakingTokenMechUsageContract.availableRewards(), - serviceStakingTokenMechUsageContract.maxNumServices(), - serviceStakingTokenMechUsageContract.getServiceIds(), - serviceStakingTokenMechUsageContract.minStakingDuration(), - serviceStakingTokenMechUsageContract.getServiceInfo(serviceId), - serviceStakingTokenMechUsageContract.getStakingState(serviceId), + serviceStakingTokenMechUsageContracts[stakingProgram].availableRewards(), + serviceStakingTokenMechUsageContracts[stakingProgram].maxNumServices(), + serviceStakingTokenMechUsageContracts[stakingProgram].getServiceIds(), + serviceStakingTokenMechUsageContracts[stakingProgram].minStakingDuration(), + serviceStakingTokenMechUsageContracts[stakingProgram].getServiceInfo( + serviceId, + ), + serviceStakingTokenMechUsageContracts[stakingProgram].getStakingState( + serviceId, + ), + serviceStakingTokenMechUsageContracts[stakingProgram].minStakingDeposit(), ]; await gnosisMulticallProvider.init(); @@ -184,6 +213,7 @@ const getStakingContractInfo = async ( minStakingDurationInBN, serviceInfo, serviceStakingState, + minStakingDeposit, ] = multicallResponse; const availableRewards = parseFloat( @@ -199,6 +229,44 @@ const getStakingContractInfo = async ( minimumStakingDuration: minStakingDurationInBN.toNumber(), serviceStakingStartTime: serviceInfo.tsStart.toNumber(), serviceStakingState, + minStakingDeposit: parseFloat(ethers.utils.formatEther(minStakingDeposit)), + }; +}; + +const getStakingContractInfoByStakingProgram = async ( + stakingProgram: StakingProgram, +) => { + const contractCalls = [ + serviceStakingTokenMechUsageContracts[stakingProgram].availableRewards(), + serviceStakingTokenMechUsageContracts[stakingProgram].maxNumServices(), + serviceStakingTokenMechUsageContracts[stakingProgram].getServiceIds(), + serviceStakingTokenMechUsageContracts[stakingProgram].minStakingDuration(), + serviceStakingTokenMechUsageContracts[stakingProgram].minStakingDeposit(), + ]; + + await gnosisMulticallProvider.init(); + + const multicallResponse = await gnosisMulticallProvider.all(contractCalls); + const [ + availableRewardsInBN, + maxNumServicesInBN, + getServiceIdsInBN, + minStakingDurationInBN, + minStakingDeposit, + ] = multicallResponse; + + const availableRewards = parseFloat( + ethers.utils.formatUnits(availableRewardsInBN, 18), + ); + const serviceIds = getServiceIdsInBN.map((id: BigNumber) => id.toNumber()); + const maxNumServices = maxNumServicesInBN.toNumber(); + + return { + availableRewards, + maxNumServices, + serviceIds, + minimumStakingDuration: minStakingDurationInBN.toNumber(), + minStakingDeposit: parseFloat(ethers.utils.formatEther(minStakingDeposit)), }; }; @@ -240,9 +308,40 @@ const getServiceRegistryInfo = async ( }; }; +const getCurrentStakingProgram = async ( + agentAddress: string, +): Promise => { + const contractCalls = [ + serviceStakingTokenMechUsageContracts[StakingProgram.Alpha].getStakingState( + agentAddress, + ), + serviceStakingTokenMechUsageContracts[StakingProgram.Beta].getStakingState( + agentAddress, + ), + ]; + + await gnosisMulticallProvider.init(); + + try { + const [isAlphaStaked, isBetaStaked] = + await gnosisMulticallProvider.all(contractCalls); + + // Alpha should take precedence, as it must be migrated from + return isAlphaStaked + ? StakingProgram.Alpha + : isBetaStaked + ? StakingProgram.Beta + : null; + } catch (error) { + return null; + } +}; + export const AutonolasService = { getAgentStakingRewardsInfo, getAvailableRewardsForEpoch, + getCurrentStakingProgram, getServiceRegistryInfo, - getStakingContractInfo, + getStakingContractInfoByServiceIdStakingProgram, + getStakingContractInfoByStakingProgram, }; From 623c6608b9e91549dead230b32edc92eb23a713a Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:10:06 +0100 Subject: [PATCH 52/99] refactor: plural addresses rename --- frontend/constants/contractAddresses.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/constants/contractAddresses.ts b/frontend/constants/contractAddresses.ts index 4969f5715..b62d32681 100644 --- a/frontend/constants/contractAddresses.ts +++ b/frontend/constants/contractAddresses.ts @@ -16,7 +16,7 @@ export const SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT_ADDRESS: Record< [Chain.GNOSIS]: '0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8', }; -export const SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESS: Record< +export const SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES: Record< number, Record > = { From 604923926f07fa99e3e3f2cdb68e65b5a3bcc2e0 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:10:25 +0100 Subject: [PATCH 53/99] feat: show new staking program alert conditionally --- frontend/components/MainPage/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index 54fc9c57d..33efe223d 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -3,9 +3,11 @@ import { Button, Card, Flex } from 'antd'; import { useEffect } from 'react'; import { Pages } from '@/enums/PageState'; +import { StakingProgram } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; import { MainHeader } from './header'; import { AddFundsSection } from './sections/AddFundsSection'; @@ -20,6 +22,7 @@ export const Main = () => { const { goto } = usePageState(); const { updateServicesState } = useServices(); const { updateBalances, isLoaded, setIsLoaded } = useBalance(); + const { currentStakingProgram } = useStakingProgram(); useEffect(() => { if (!isLoaded) { @@ -50,7 +53,9 @@ export const Main = () => { style={{ borderTopColor: 'transparent' }} > - + {currentStakingProgram === StakingProgram.Alpha && ( + + )} From 207c7ce0513cb9b4779fb03bb9dca20063d1af97 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:10:49 +0100 Subject: [PATCH 54/99] refactor: replace mocked contracts data --- .../components/ManageStakingPage/index.tsx | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/frontend/components/ManageStakingPage/index.tsx b/frontend/components/ManageStakingPage/index.tsx index 9650564de..45ed4f2d2 100644 --- a/frontend/components/ManageStakingPage/index.tsx +++ b/frontend/components/ManageStakingPage/index.tsx @@ -1,33 +1,34 @@ import { CloseOutlined } from '@ant-design/icons'; import { Button, Card } from 'antd'; +import { Chain } from '@/client'; +import { SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES } from '@/constants/contractAddresses'; import { Pages } from '@/enums/PageState'; -import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; +import { StakingProgram } from '@/enums/StakingProgram'; import { usePageState } from '@/hooks/usePageState'; -import { StakingProgram } from '@/types/StakingProgram'; import { CardTitle } from '../Card/CardTitle'; -import { StakingContract } from './StakingContract'; +import { StakingContractSection } from './StakingContract'; import { WhatAreStakingContractsSection } from './WhatAreStakingContracts'; -const mockStakingContracts: StakingProgram[] = [ - { - name: 'Pearl Beta', - rewardsPerWorkPeriod: 0.14, - requiredOlasForStaking: 40, - isEnoughSlots: true, - status: StakingProgramStatus.New, - contractAddress: '0x1234567890', - }, - { - name: 'Pearl Alpha', - rewardsPerWorkPeriod: 0.047, - requiredOlasForStaking: 20, - isEnoughSlots: true, - status: StakingProgramStatus.Selected, - contractAddress: '0x0987654321', - }, -]; +// const mockStakingContracts: StakingProgram[] = [ +// { +// name: 'Pearl Beta', +// rewardsPerWorkPeriod: 0.14, +// requiredOlasForStaking: 40, +// isEnoughSlots: true, +// status: StakingProgramStatus.New, +// contractAddress: '0x1234567890', +// }, +// { +// name: 'Pearl Alpha', +// rewardsPerWorkPeriod: 0.047, +// requiredOlasForStaking: 20, +// isEnoughSlots: true, +// status: StakingProgramStatus.Selected, +// contractAddress: '0x0987654321', +// }, +// ]; export const ManageStakingPage = () => { const { goto } = usePageState(); @@ -44,8 +45,14 @@ export const ManageStakingPage = () => { } > - {mockStakingContracts.map((contract) => ( - + {Object.entries( + SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS], + ).map(([stakingProgram, contractAddress]) => ( + ))} ); From 8bfbf49a159e3d49647b0a81a5b89c006356e48d Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:11:18 +0100 Subject: [PATCH 55/99] refactor: progress on staking contract sections, replacing mocked data --- .../StakingContract/index.tsx | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContract/index.tsx b/frontend/components/ManageStakingPage/StakingContract/index.tsx index d7c2762d8..ba52137e5 100644 --- a/frontend/components/ManageStakingPage/StakingContract/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContract/index.tsx @@ -4,9 +4,10 @@ import styled from 'styled-components'; import { CardSection } from '@/components/styled/CardSection'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; +import { StakingProgram } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; -import { StakingProgram } from '@/types/StakingProgram'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; +import { Address } from '@/types/Address'; import { AlertInsufficientMigrationFunds, @@ -40,11 +41,22 @@ const ContractParameter = ({ ); -export const StakingContract = ({ contract }: { contract: StakingProgram }) => { +export const StakingContractSection = ({ + stakingProgram, + contractAddress, +}: { + stakingProgram: StakingProgram; + contractAddress: Address; +}) => { + const { currentStakingProgram } = useStakingProgram(); + const { token } = useToken(); const { totalOlasBalance, isBalanceLoaded } = useBalance(); - const isSelected = contract.status === StakingProgramStatus.Selected; + const isSelected = + currentStakingProgram && currentStakingProgram === stakingProgram; + + const stakingContractInfo = useMemo(() => {}, []); const isEnoughOlas = useMemo(() => { if (totalOlasBalance === undefined) return false; From 50d688bc0496472f21c6df19e1b89898615c28fd Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:11:54 +0100 Subject: [PATCH 56/99] refactor: use stakingContractMeta in staking contract sections --- .../SettingsPage/StakingContractSection.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/frontend/components/SettingsPage/StakingContractSection.tsx b/frontend/components/SettingsPage/StakingContractSection.tsx index 420288786..a762e3e20 100644 --- a/frontend/components/SettingsPage/StakingContractSection.tsx +++ b/frontend/components/SettingsPage/StakingContractSection.tsx @@ -1,5 +1,7 @@ import { Button, Flex, Typography } from 'antd'; +import { Chain } from '@/client'; +import { SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES } from '@/constants/contractAddresses'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { Pages } from '@/enums/PageState'; import { usePageState } from '@/hooks/usePageState'; @@ -11,14 +13,24 @@ const { Text } = Typography; export const StakingContractSection = () => { const { goto } = usePageState(); - const { currentStakingProgram } = useStakingProgram(); + const { + currentStakingProgram, + currentStakingProgramMeta, + defaultStakingProgram, + } = useStakingProgram(); + + const stakingContractAddress = + SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS][ + currentStakingProgram ?? defaultStakingProgram + ]; + return ( Staking contract - {currentStakingProgram.name} + {currentStakingProgramMeta.name} Contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} From a4020b61e73b62d096c46f447cdf1f0fab1806cc Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:12:12 +0100 Subject: [PATCH 57/99] feat: add staking contract meta for hardcode textual data --- frontend/constants/stakingProgramMeta.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 frontend/constants/stakingProgramMeta.ts diff --git a/frontend/constants/stakingProgramMeta.ts b/frontend/constants/stakingProgramMeta.ts new file mode 100644 index 000000000..f060c3ab2 --- /dev/null +++ b/frontend/constants/stakingProgramMeta.ts @@ -0,0 +1,15 @@ +import { StakingProgram } from '@/enums/StakingProgram'; + +export const STAKING_PROGRAM_META: Record< + StakingProgram, + { + name: string; + } +> = { + [StakingProgram.Alpha]: { + name: 'Pearl Alpha', + }, + [StakingProgram.Beta]: { + name: 'Pearl Beta', + }, +}; From e8132a6490bf7e3d0113ac0ecb5b1aebf938b467 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:12:37 +0100 Subject: [PATCH 58/99] refactor: multicontract support for rewards --- frontend/context/RewardProvider.tsx | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/frontend/context/RewardProvider.tsx b/frontend/context/RewardProvider.tsx index 0e67a002a..6a27c1d76 100644 --- a/frontend/context/RewardProvider.tsx +++ b/frontend/context/RewardProvider.tsx @@ -17,6 +17,7 @@ import { AutonolasService } from '@/service/Autonolas'; import { OnlineStatusContext } from './OnlineStatusProvider'; import { ServicesContext } from './ServicesProvider'; +import { StakingProgramContext } from './StakingProgramContext'; export const RewardContext = createContext<{ accruedServiceStakingRewards?: number; @@ -42,6 +43,9 @@ export const RewardProvider = ({ children }: PropsWithChildren) => { const service = useMemo(() => services?.[0], [services]); const { storeState } = useStore(); const electronApi = useElectronApi(); + const { currentStakingProgram, defaultStakingProgram } = useContext( + StakingProgramContext, + ); const [accruedServiceStakingRewards, setAccruedServiceStakingRewards] = useState(); @@ -68,14 +72,25 @@ export const RewardProvider = ({ children }: PropsWithChildren) => { const updateRewards = useCallback(async (): Promise => { let stakingRewardsInfoPromise; - if (service?.chain_data?.multisig && service?.chain_data?.token) { + + // only check for rewards if there's a currentStakingProgram active + if ( + currentStakingProgram && + service?.chain_data?.multisig && + service?.chain_data?.token + ) { stakingRewardsInfoPromise = AutonolasService.getAgentStakingRewardsInfo({ agentMultisigAddress: service?.chain_data?.multisig, serviceId: service?.chain_data?.token, + stakingProgram: currentStakingProgram, }); } - const epochRewardsPromise = AutonolasService.getAvailableRewardsForEpoch(); + // can fallback to default staking program if no current staking program is active + const epochRewardsPromise = AutonolasService.getAvailableRewardsForEpoch( + currentStakingProgram ?? defaultStakingProgram, + ); + const [stakingRewardsInfo, rewards] = await Promise.all([ stakingRewardsInfoPromise, epochRewardsPromise, @@ -86,7 +101,12 @@ export const RewardProvider = ({ children }: PropsWithChildren) => { stakingRewardsInfo?.accruedServiceStakingRewards, ); setAvailableRewardsForEpoch(rewards); - }, [service]); + }, [ + currentStakingProgram, + defaultStakingProgram, + service?.chain_data?.multisig, + service?.chain_data?.token, + ]); useEffect(() => { if (isEligibleForRewards && !storeState?.firstStakingRewardAchieved) { From 175c321b516af2d79d3cbe74a8dd9dd73e496f56 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:13:06 +0100 Subject: [PATCH 59/99] feat: extend staking contract info provider with current staking program detection .etc --- .../context/StakingContractInfoProvider.tsx | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/frontend/context/StakingContractInfoProvider.tsx b/frontend/context/StakingContractInfoProvider.tsx index 20d56ac2f..2417c2c0f 100644 --- a/frontend/context/StakingContractInfoProvider.tsx +++ b/frontend/context/StakingContractInfoProvider.tsx @@ -9,10 +9,12 @@ import { import { useInterval } from 'usehooks-ts'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { StakingProgram } from '@/enums/StakingProgram'; import { AutonolasService } from '@/service/Autonolas'; import { StakingContractInfo } from '@/types/Autonolas'; import { ServicesContext } from './ServicesProvider'; +import { StakingProgramContext } from './StakingProgramContext'; type StakingContractInfoContextProps = { updateStakingContractInfo: () => Promise; @@ -29,27 +31,38 @@ export const StakingContractInfoProvider = ({ children, }: PropsWithChildren) => { const { services } = useContext(ServicesContext); + const { currentStakingProgram } = useContext(StakingProgramContext); + + const [stakingContractInfoRecord, setStakingContractInfoRecord] = + useState>(); + const serviceId = useMemo(() => services?.[0]?.chain_data?.token, [services]); - const [stakingContractInfo, setStakingContractInfo] = + const [currentStakingContractInfo, setStakingContractInfo] = useState(); - const updateStakingContractInfo = useCallback(async () => { + // CURRENT staking contract info should be updated on interval + const updateCurrentStakingContractInfo = useCallback(async () => { if (!serviceId) return; - const info = await AutonolasService.getStakingContractInfo(serviceId); + if (!currentStakingProgram) return; + const info = + await AutonolasService.getStakingContractInfoByServiceIdStakingProgram( + serviceId, + currentStakingProgram, + ); if (!info) return; setStakingContractInfo(info); - }, [serviceId]); + }, [currentStakingProgram, serviceId]); - useInterval(updateStakingContractInfo, FIVE_SECONDS_INTERVAL); + useInterval(updateCurrentStakingContractInfo, FIVE_SECONDS_INTERVAL); return ( {children} From 5bdb80f154ee85d901fe5a924883cf8122b76a51 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:13:32 +0100 Subject: [PATCH 60/99] feat: add context for staking program data; current, default, and update methods --- frontend/context/StakingProgramContext.tsx | 52 ++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 frontend/context/StakingProgramContext.tsx diff --git a/frontend/context/StakingProgramContext.tsx b/frontend/context/StakingProgramContext.tsx new file mode 100644 index 000000000..93c3c721a --- /dev/null +++ b/frontend/context/StakingProgramContext.tsx @@ -0,0 +1,52 @@ +import { createContext, PropsWithChildren, useCallback, useState } from 'react'; + +import { StakingProgram } from '@/enums/StakingProgram'; +import { useServices } from '@/hooks/useServices'; +import { AutonolasService } from '@/service/Autonolas'; + +export const StakingProgramContext = createContext<{ + currentStakingProgram?: StakingProgram | null; + defaultStakingProgram: StakingProgram; + updateStakingProgram: () => Promise; +}>({ + currentStakingProgram: undefined, + defaultStakingProgram: StakingProgram.Beta, + updateStakingProgram: async () => {}, +}); + +/** Determines the current active staking program, if any */ +export const StakingProgramProvider = ({ children }: PropsWithChildren) => { + const { service } = useServices(); + + const [currentStakingProgram, setCurrentStakingProgram] = + useState(); + + const updateStakingProgram = useCallback(async () => { + // if no service / instance is available, we don't need to check for staking program + if (!service?.chain_data?.instances?.[0]) { + setCurrentStakingProgram(null); + return; + } + + // TODO: check if assuming the first service is the correct approach + const operatorAddress = service?.chain_data?.instances?.[0]; + if (operatorAddress) { + // if service exists, we need to check if it is staked + AutonolasService.getCurrentStakingProgram(operatorAddress).then( + setCurrentStakingProgram, + ); + } + }, [service]); + + return ( + + {children} + + ); +}; From 154aa72fd1711862c06a51429709608f0182b713 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:13:47 +0100 Subject: [PATCH 61/99] feat: hook for staking program context --- frontend/hooks/useStakingProgram.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index eca089948..75f3914f8 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -1,24 +1,21 @@ -import { useState } from 'react'; +import { useContext, useState } from 'react'; -import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; -import { StakingProgram } from '@/types/StakingProgram'; +import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; +import { StakingProgramContext } from '@/context/StakingProgramContext'; /** * Mock hook for staking program abstraction * @returns {currentStakingProgram: IncentiveProgram} */ export const useStakingProgram = () => { + const { currentStakingProgram, defaultStakingProgram } = useContext( + StakingProgramContext, + ); + const [isMigrating, setIsMigrating] = useState(false); - // TODO: Calculate current staking program - // from current staking contract address - const currentStakingProgram: StakingProgram = { - name: 'Pearl Alpha', - status: StakingProgramStatus.Selected, - contractAddress: '0x', - rewardsPerWorkPeriod: 0.25, - requiredOlasForStaking: 20, - }; + const currentStakingProgramMeta = + STAKING_PROGRAM_META[currentStakingProgram ?? defaultStakingProgram]; // TODO: Implement migration logic const migrate = async () => { @@ -30,6 +27,8 @@ export const useStakingProgram = () => { return { currentStakingProgram, + currentStakingProgramMeta, + defaultStakingProgram, isMigrating, migrate, }; From 04c4f02f7cdf67b0daed7f89826b6c2d9b7febbb Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 12:14:09 +0100 Subject: [PATCH 62/99] feat: staking program provider in _app --- frontend/pages/_app.tsx | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 68727cf8c..94e588e6d 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -15,6 +15,7 @@ import { ServicesProvider } from '@/context/ServicesProvider'; import { SettingsProvider } from '@/context/SettingsProvider'; import { SetupProvider } from '@/context/SetupProvider'; import { StakingContractInfoProvider } from '@/context/StakingContractInfoProvider'; +import { StakingProgramProvider } from '@/context/StakingProgramContext'; import { StoreProvider } from '@/context/StoreProvider'; import { WalletProvider } from '@/context/WalletProvider'; import { mainTheme } from '@/theme'; @@ -37,15 +38,17 @@ export default function App({ Component, pageProps }: AppProps) { - - - {isMounted ? ( - - - - ) : null} - - + + + + {isMounted ? ( + + + + ) : null} + + + From 65d1dc7bdc0542f540a46ce5ca9332b56ffc7655 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 13:12:23 +0100 Subject: [PATCH 63/99] feat: staking program hooks and context --- .../context/StakingContractInfoProvider.tsx | 74 +++++++++++++------ frontend/context/StakingProgramContext.tsx | 8 +- frontend/hooks/useStakingContractInfo.ts | 11 ++- frontend/hooks/useStakingProgram.ts | 10 +-- 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/frontend/context/StakingContractInfoProvider.tsx b/frontend/context/StakingContractInfoProvider.tsx index 2417c2c0f..10ba73ede 100644 --- a/frontend/context/StakingContractInfoProvider.tsx +++ b/frontend/context/StakingContractInfoProvider.tsx @@ -3,6 +3,7 @@ import { PropsWithChildren, useCallback, useContext, + useEffect, useMemo, useState, } from 'react'; @@ -17,52 +18,79 @@ import { ServicesContext } from './ServicesProvider'; import { StakingProgramContext } from './StakingProgramContext'; type StakingContractInfoContextProps = { - updateStakingContractInfo: () => Promise; - stakingContractInfo?: StakingContractInfo; + updateActiveStakingContractInfo: () => Promise; + activeStakingContractInfo?: StakingContractInfo; + stakingContractInfoRecord?: Record< + StakingProgram, + Partial + >; }; export const StakingContractInfoContext = createContext({ - updateStakingContractInfo: async () => {}, - stakingContractInfo: undefined, + updateActiveStakingContractInfo: async () => {}, + activeStakingContractInfo: undefined, + stakingContractInfoRecord: undefined, }); export const StakingContractInfoProvider = ({ children, }: PropsWithChildren) => { const { services } = useContext(ServicesContext); - const { currentStakingProgram } = useContext(StakingProgramContext); + const { activeStakingProgram } = useContext(StakingProgramContext); + + const [activeStakingContractInfo, setActiveStakingContractInfo] = + useState(); const [stakingContractInfoRecord, setStakingContractInfoRecord] = - useState>(); + useState>>(); const serviceId = useMemo(() => services?.[0]?.chain_data?.token, [services]); - const [currentStakingContractInfo, setStakingContractInfo] = - useState(); - - // CURRENT staking contract info should be updated on interval - const updateCurrentStakingContractInfo = useCallback(async () => { + // ACTIVE staking contract info should be updated on interval + // it requires serviceId and activeStakingProgram + const updateActiveStakingContractInfo = useCallback(async () => { if (!serviceId) return; + if (!activeStakingProgram) return; + + AutonolasService.getStakingContractInfoByServiceIdStakingProgram( + serviceId, + activeStakingProgram, + ).then(setActiveStakingContractInfo); + }, [activeStakingProgram, serviceId]); + + useInterval(updateActiveStakingContractInfo, FIVE_SECONDS_INTERVAL); - if (!currentStakingProgram) return; - const info = - await AutonolasService.getStakingContractInfoByServiceIdStakingProgram( - serviceId, - currentStakingProgram, - ); - if (!info) return; + // Record of staking contract info for each staking program + // not user/service specific + const updateStakingContractInfoRecord = () => { + const alpha = AutonolasService.getStakingContractInfoByStakingProgram( + StakingProgram.Alpha, + ); + const beta = AutonolasService.getStakingContractInfoByStakingProgram( + StakingProgram.Beta, + ); - setStakingContractInfo(info); - }, [currentStakingProgram, serviceId]); + Promise.all([alpha, beta]).then((values) => { + const [alphaInfo, betaInfo] = values; + setStakingContractInfoRecord({ + [StakingProgram.Alpha]: alphaInfo, + [StakingProgram.Beta]: betaInfo, + }); + }); + }; - useInterval(updateCurrentStakingContractInfo, FIVE_SECONDS_INTERVAL); + useEffect(() => { + // Load staking contract info record on mount + updateStakingContractInfoRecord(); + }, []); return ( {children} diff --git a/frontend/context/StakingProgramContext.tsx b/frontend/context/StakingProgramContext.tsx index 93c3c721a..386c20b5d 100644 --- a/frontend/context/StakingProgramContext.tsx +++ b/frontend/context/StakingProgramContext.tsx @@ -5,11 +5,11 @@ import { useServices } from '@/hooks/useServices'; import { AutonolasService } from '@/service/Autonolas'; export const StakingProgramContext = createContext<{ - currentStakingProgram?: StakingProgram | null; + activeStakingProgram?: StakingProgram | null; defaultStakingProgram: StakingProgram; updateStakingProgram: () => Promise; }>({ - currentStakingProgram: undefined, + activeStakingProgram: undefined, defaultStakingProgram: StakingProgram.Beta, updateStakingProgram: async () => {}, }); @@ -18,7 +18,7 @@ export const StakingProgramContext = createContext<{ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { const { service } = useServices(); - const [currentStakingProgram, setCurrentStakingProgram] = + const [activeStakingProgram, setCurrentStakingProgram] = useState(); const updateStakingProgram = useCallback(async () => { @@ -41,7 +41,7 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { return ( { - const { stakingContractInfo } = useContext(StakingContractInfoContext); + const { activeStakingContractInfo, stakingContractInfoRecord } = useContext( + StakingContractInfoContext, + ); + const { services } = useServices(); - if (!services?.[0] || !stakingContractInfo) return {}; + if (!services?.[0] || !activeStakingContractInfo) + return { stakingContractInfoRecord }; const { serviceStakingState, @@ -17,7 +21,7 @@ export const useStakingContractInfo = () => { serviceIds, maxNumServices, minimumStakingDuration, - } = stakingContractInfo; + } = activeStakingContractInfo; const isRewardsAvailable = availableRewards > 0; const hasEnoughServiceSlots = serviceIds.length < maxNumServices; @@ -55,5 +59,6 @@ export const useStakingContractInfo = () => { isEligibleForStaking, isRewardsAvailable, isAgentEvicted, + stakingContractInfoRecord, }; }; diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index 75f3914f8..af04920ed 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -8,14 +8,14 @@ import { StakingProgramContext } from '@/context/StakingProgramContext'; * @returns {currentStakingProgram: IncentiveProgram} */ export const useStakingProgram = () => { - const { currentStakingProgram, defaultStakingProgram } = useContext( + const { activeStakingProgram, defaultStakingProgram } = useContext( StakingProgramContext, ); const [isMigrating, setIsMigrating] = useState(false); - const currentStakingProgramMeta = - STAKING_PROGRAM_META[currentStakingProgram ?? defaultStakingProgram]; + const activeStakingProgramMeta = + STAKING_PROGRAM_META[activeStakingProgram ?? defaultStakingProgram]; // TODO: Implement migration logic const migrate = async () => { @@ -26,8 +26,8 @@ export const useStakingProgram = () => { }; return { - currentStakingProgram, - currentStakingProgramMeta, + activeStakingProgram, + activeStakingProgramMeta, defaultStakingProgram, isMigrating, migrate, From 99365e80d3974b22646fe1dc59896b8f2b1669ce Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 13:12:37 +0100 Subject: [PATCH 64/99] refactor: main page conditions and modals --- frontend/components/MainPage/index.tsx | 2 +- .../components/MainPage/modals/MigrationModal.tsx | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index 33efe223d..f97acf159 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -22,7 +22,7 @@ export const Main = () => { const { goto } = usePageState(); const { updateServicesState } = useServices(); const { updateBalances, isLoaded, setIsLoaded } = useBalance(); - const { currentStakingProgram } = useStakingProgram(); + const { activeStakingProgram: currentStakingProgram } = useStakingProgram(); useEffect(() => { if (!isLoaded) { diff --git a/frontend/components/MainPage/modals/MigrationModal.tsx b/frontend/components/MainPage/modals/MigrationModal.tsx index 2b7afe6c8..30b3b2e08 100644 --- a/frontend/components/MainPage/modals/MigrationModal.tsx +++ b/frontend/components/MainPage/modals/MigrationModal.tsx @@ -1,6 +1,7 @@ import { Button, Flex, Modal, Typography } from 'antd'; import Image from 'next/image'; +import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { useStakingProgram } from '@/hooks/useStakingProgram'; @@ -11,7 +12,15 @@ export const MigrationSuccessModal = ({ open: boolean; onClose: () => void; }) => { - const { currentStakingProgram } = useStakingProgram(); + const { activeStakingProgram } = useStakingProgram(); + + // Close modal if no active staking program, migration doesn't apply to non-stakers + if (!activeStakingProgram) { + onClose(); + return null; + } + + const activeStakingProgramMeta = STAKING_PROGRAM_META[activeStakingProgram]; return ( - Your agent is now staked on {currentStakingProgram.name}. + Your agent is now staked on {activeStakingProgramMeta.name}. {/* TODO: Add relevant block explorer domain */} From 5de93a4e208292c09adb3d65b6bbdd5d2585a85b Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 13:12:56 +0100 Subject: [PATCH 65/99] refactor: staking contract section --- .../StakingContract/StakingContractTag.tsx | 2 +- .../StakingContract/index.tsx | 79 ++++++++++++------- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContract/StakingContractTag.tsx b/frontend/components/ManageStakingPage/StakingContract/StakingContractTag.tsx index 857dd4f56..b09c11a05 100644 --- a/frontend/components/ManageStakingPage/StakingContract/StakingContractTag.tsx +++ b/frontend/components/ManageStakingPage/StakingContract/StakingContractTag.tsx @@ -5,7 +5,7 @@ import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; export const StakingContractTag = ({ status, }: { - status: StakingProgramStatus; + status?: StakingProgramStatus; }) => { if (status === StakingProgramStatus.New) { return New; diff --git a/frontend/components/ManageStakingPage/StakingContract/index.tsx b/frontend/components/ManageStakingPage/StakingContract/index.tsx index ba52137e5..230ba6689 100644 --- a/frontend/components/ManageStakingPage/StakingContract/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContract/index.tsx @@ -3,9 +3,11 @@ import { useMemo } from 'react'; import styled from 'styled-components'; import { CardSection } from '@/components/styled/CardSection'; +import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { StakingProgram } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; +import { useStakingContractInfo } from '@/hooks/useStakingContractInfo'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { Address } from '@/types/Address'; @@ -48,27 +50,39 @@ export const StakingContractSection = ({ stakingProgram: StakingProgram; contractAddress: Address; }) => { - const { currentStakingProgram } = useStakingProgram(); - + const { activeStakingProgram } = useStakingProgram(); + const { stakingContractInfoRecord } = useStakingContractInfo(); const { token } = useToken(); const { totalOlasBalance, isBalanceLoaded } = useBalance(); - const isSelected = - currentStakingProgram && currentStakingProgram === stakingProgram; + const stakingContractInfo = stakingContractInfoRecord?.[stakingProgram]; - const stakingContractInfo = useMemo(() => {}, []); + const activeStakingProgramMeta = STAKING_PROGRAM_META[stakingProgram]; - const isEnoughOlas = useMemo(() => { + const isSelected = + activeStakingProgram && activeStakingProgram === stakingProgram; + + const hasEnoughOlas = useMemo(() => { if (totalOlasBalance === undefined) return false; - return totalOlasBalance > contract.requiredOlasForStaking; - }, [totalOlasBalance, contract.requiredOlasForStaking]); + if (!stakingContractInfo) return false; + if (!stakingContractInfo.minStakingDeposit) return false; + return totalOlasBalance > stakingContractInfo?.minStakingDeposit; + }, [stakingContractInfo, totalOlasBalance]); + + const hasEnoughSlots = + stakingContractInfo?.maxNumServices && + stakingContractInfo?.serviceIds && + stakingContractInfo?.maxNumServices > + stakingContractInfo?.serviceIds?.length; + + // TODO: compatibility needs to be implemented const isAppVersionCompatible = true; // contract.appVersion === 'rc105'; const isMigratable = !isSelected && isBalanceLoaded && - contract.isEnoughSlots && - isEnoughOlas && + hasEnoughSlots && + hasEnoughOlas && isAppVersionCompatible; const cantMigrateAlert = useMemo(() => { @@ -76,11 +90,11 @@ export const StakingContractSection = ({ return null; } - if (!contract.isEnoughSlots) { + if (!hasEnoughSlots) { return ; } - if (!isEnoughOlas) { + if (!hasEnoughOlas) { return ( ); @@ -93,8 +107,8 @@ export const StakingContractSection = ({ isSelected, isBalanceLoaded, totalOlasBalance, - contract.isEnoughSlots, - isEnoughOlas, + hasEnoughSlots, + hasEnoughOlas, isAppVersionCompatible, ]); @@ -110,13 +124,14 @@ export const StakingContractSection = ({ {`${contract.name} contract`} - + >{`${activeStakingProgramMeta.name} contract`} + {/* TODO: pass `status` attribute */} + {!isSelected && ( // here instead of isSelected we should check that the contract is not the old staking contract // but the one from staking factory (if we want to open govern) @@ -124,21 +139,29 @@ export const StakingContractSection = ({ )} - {/* Contract details */} - - - {/* "Can't migrate" Alert */} + + {/* TODO: fix */} + + {/* Contract details + {stakingContractInfo?.availableRewards && ( + + )} + + {stakingContractInfo?.minStakingDeposit && ( + + )} */} + {cantMigrateAlert} {/* Switch to program button */} {!isSelected && ( )} From e9946e8be18d4b14f8bcac3fd12a5d81f436bdbf Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 13:12:57 +0100 Subject: [PATCH 66/99] --- --- frontend/components/SettingsPage/StakingContractSection.tsx | 4 ++-- frontend/constants/contractAddresses.ts | 3 ++- frontend/context/RewardProvider.tsx | 5 ++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/components/SettingsPage/StakingContractSection.tsx b/frontend/components/SettingsPage/StakingContractSection.tsx index a762e3e20..d1e9c6a3f 100644 --- a/frontend/components/SettingsPage/StakingContractSection.tsx +++ b/frontend/components/SettingsPage/StakingContractSection.tsx @@ -14,8 +14,8 @@ const { Text } = Typography; export const StakingContractSection = () => { const { goto } = usePageState(); const { - currentStakingProgram, - currentStakingProgramMeta, + activeStakingProgram: currentStakingProgram, + activeStakingProgramMeta: currentStakingProgramMeta, defaultStakingProgram, } = useStakingProgram(); diff --git a/frontend/constants/contractAddresses.ts b/frontend/constants/contractAddresses.ts index b62d32681..bf76ee672 100644 --- a/frontend/constants/contractAddresses.ts +++ b/frontend/constants/contractAddresses.ts @@ -21,8 +21,9 @@ export const SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES: Record< Record > = { [Chain.GNOSIS]: { - [StakingProgram.Alpha]: '0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A', + // Maintain order, as it is used in the UI [StakingProgram.Beta]: '0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d', + [StakingProgram.Alpha]: '0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A', }, }; diff --git a/frontend/context/RewardProvider.tsx b/frontend/context/RewardProvider.tsx index 6a27c1d76..534659e67 100644 --- a/frontend/context/RewardProvider.tsx +++ b/frontend/context/RewardProvider.tsx @@ -43,9 +43,8 @@ export const RewardProvider = ({ children }: PropsWithChildren) => { const service = useMemo(() => services?.[0], [services]); const { storeState } = useStore(); const electronApi = useElectronApi(); - const { currentStakingProgram, defaultStakingProgram } = useContext( - StakingProgramContext, - ); + const { activeStakingProgram: currentStakingProgram, defaultStakingProgram } = + useContext(StakingProgramContext); const [accruedServiceStakingRewards, setAccruedServiceStakingRewards] = useState(); From d096c6ca60c8a3ec3d092c10baf076efca005265 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 13:13:35 +0100 Subject: [PATCH 67/99] refactor: reward provider --- frontend/context/RewardProvider.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/frontend/context/RewardProvider.tsx b/frontend/context/RewardProvider.tsx index 534659e67..589db9d6a 100644 --- a/frontend/context/RewardProvider.tsx +++ b/frontend/context/RewardProvider.tsx @@ -43,8 +43,9 @@ export const RewardProvider = ({ children }: PropsWithChildren) => { const service = useMemo(() => services?.[0], [services]); const { storeState } = useStore(); const electronApi = useElectronApi(); - const { activeStakingProgram: currentStakingProgram, defaultStakingProgram } = - useContext(StakingProgramContext); + const { activeStakingProgram, defaultStakingProgram } = useContext( + StakingProgramContext, + ); const [accruedServiceStakingRewards, setAccruedServiceStakingRewards] = useState(); @@ -74,20 +75,20 @@ export const RewardProvider = ({ children }: PropsWithChildren) => { // only check for rewards if there's a currentStakingProgram active if ( - currentStakingProgram && + activeStakingProgram && service?.chain_data?.multisig && service?.chain_data?.token ) { stakingRewardsInfoPromise = AutonolasService.getAgentStakingRewardsInfo({ agentMultisigAddress: service?.chain_data?.multisig, serviceId: service?.chain_data?.token, - stakingProgram: currentStakingProgram, + stakingProgram: activeStakingProgram, }); } // can fallback to default staking program if no current staking program is active const epochRewardsPromise = AutonolasService.getAvailableRewardsForEpoch( - currentStakingProgram ?? defaultStakingProgram, + activeStakingProgram ?? defaultStakingProgram, ); const [stakingRewardsInfo, rewards] = await Promise.all([ @@ -101,7 +102,7 @@ export const RewardProvider = ({ children }: PropsWithChildren) => { ); setAvailableRewardsForEpoch(rewards); }, [ - currentStakingProgram, + activeStakingProgram, defaultStakingProgram, service?.chain_data?.multisig, service?.chain_data?.token, From 64a31842c8f36e36b78203131384a01888fb1570 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 16:17:24 +0100 Subject: [PATCH 68/99] refactor: update chain data types --- frontend/client/types.ts | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index ac244afd3..fc5d7fe72 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -1,3 +1,4 @@ +import { StakingProgram } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; import { Chain, DeploymentStatus, Ledger } from './enums'; @@ -20,6 +21,19 @@ export type ChainData = { instances?: Address[]; token?: number; multisig?: Address; + on_chain_state: number; + staked: boolean; + user_params: { + cost_of_bond: number; + fund_requirements: { + agent: number; + safe: number; + }; + nft: string; + staking_program_id: StakingProgram; + threshold: number; + use_staking: true; + }; }; export type Service = { @@ -27,8 +41,12 @@ export type Service = { hash: string; keys: ServiceKeys[]; readme?: string; - ledger: LedgerConfig; - chain_data: ChainData; + chain_configs: { + [chainId: number]: { + ledger_config: LedgerConfig; + chain_data: ChainData; + }; + }; }; export type ServiceTemplate = { @@ -43,13 +61,13 @@ export type ServiceTemplate = { }; export type ConfigurationTemplate = { + rpc?: string; // added on deployment + staking_program_id?: StakingProgram; // added on deployment nft: string; - rpc?: string; // added by user agent_id: number; threshold: number; use_staking: boolean; - cost_of_bond: number; // TODO: REQUEST RESET TO NAMING CONVENTION, OLAS_COST_OF_BOND - olas_required_to_stake: number; // TODO: CLARIFY WHY THIS WAS REMOVED + cost_of_bond: number; monthly_gas_estimate: number; fund_requirements: FundRequirementsTemplate; }; From ba68ea0c54151640459f6e5817fdf7d19a89e2f6 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 16:17:47 +0100 Subject: [PATCH 69/99] refactor: fix agent button constants --- .../MainPage/header/AgentButton.tsx | 28 ++++++++++++++----- .../components/MainPage/header/constants.ts | 16 ----------- .../StakingContract/index.tsx | 27 ++++++++++++++++-- .../SettingsPage/DebugInfoSection.tsx | 14 ++++++---- frontend/constants/serviceTemplates.ts | 5 ++-- frontend/context/BalanceProvider.tsx | 4 ++- frontend/context/ServicesProvider.tsx | 14 +++++++--- frontend/service/Services.ts | 16 +++++++---- frontend/utils/service.ts | 8 +----- 9 files changed, 82 insertions(+), 50 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton.tsx index 7f689d92a..3db3f053b 100644 --- a/frontend/components/MainPage/header/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton.tsx @@ -21,7 +21,7 @@ import { CannotStartAgentDueToUnexpectedError, CannotStartAgentPopover, } from './CannotStartAgentPopover'; -import { requiredGas, requiredOlas } from './constants'; +import { requiredGas } from './constants'; const { Text } = Typography; @@ -106,7 +106,14 @@ const AgentNotRunningButton = () => { totalEthBalance, } = useBalance(); const { storeState } = useStore(); - const { isEligibleForStaking, isAgentEvicted } = useStakingContractInfo(); + const { isEligibleForStaking, isAgentEvicted, stakingContractInfoRecord } = + useStakingContractInfo(); + const { activeStakingProgram, defaultStakingProgram } = useStakingProgram(); + + const minStakingDeposit = + stakingContractInfoRecord?.[activeStakingProgram ?? defaultStakingProgram] + ?.minStakingDeposit; + const requiredOlas = minStakingDeposit && minStakingDeposit * 2; const safeOlasBalance = safeBalance?.OLAS; const safeOlasBalanceWithStaked = @@ -144,10 +151,12 @@ const AgentNotRunningButton = () => { // Then create / deploy the service try { await ServicesService.createService({ + stakingProgram: activeStakingProgram ?? defaultStakingProgram, serviceTemplate, deploy: true, }); } catch (error) { + 0; console.error(error); setServiceStatus(undefined); showNotification?.('Error while deploying service'); @@ -185,6 +194,8 @@ const AgentNotRunningButton = () => { setServiceStatus, masterSafeAddress, showNotification, + activeStakingProgram, + defaultStakingProgram, serviceTemplate, service, ]); @@ -203,6 +214,8 @@ const AgentNotRunningButton = () => { if (serviceStatus === DeploymentStatus.DEPLOYING) return false; if (serviceStatus === DeploymentStatus.STOPPING) return false; + if (!requiredOlas) return false; + // case where service exists & user has initial funded if (service && storeState?.isInitialFunded) { if (!safeOlasBalanceWithStaked) return false; @@ -218,14 +231,15 @@ const AgentNotRunningButton = () => { return hasEnoughOlas && hasEnoughEth; }, [ - isAgentEvicted, - isEligibleForStaking, - safeOlasBalanceWithStaked, - service, serviceStatus, + safeBalance, + service, storeState?.isInitialFunded, + isEligibleForStaking, + isAgentEvicted, + safeOlasBalanceWithStaked, + requiredOlas, totalEthBalance, - safeBalance, ]); const buttonProps: ButtonProps = { diff --git a/frontend/components/MainPage/header/constants.ts b/frontend/components/MainPage/header/constants.ts index a9e9a098a..101e61590 100644 --- a/frontend/components/MainPage/header/constants.ts +++ b/frontend/components/MainPage/header/constants.ts @@ -3,22 +3,6 @@ import { formatUnits } from 'ethers/lib/utils'; import { CHAINS } from '@/constants/chains'; import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; -// TODO: Move this to more appropriate location (root /constants) -const olasCostOfBond = Number( - formatUnits( - `${SERVICE_TEMPLATES[0].configurations[CHAINS.GNOSIS.chainId].cost_of_bond}`, - 18, - ), -); - -const olasRequiredToStake = Number( - formatUnits( - `${SERVICE_TEMPLATES[0].configurations[CHAINS.GNOSIS.chainId].olas_required_to_stake}`, - 18, - ), -); - -export const requiredOlas = olasCostOfBond + olasRequiredToStake; export const requiredGas = Number( formatUnits( `${SERVICE_TEMPLATES[0].configurations[CHAINS.GNOSIS.chainId].monthly_gas_estimate}`, diff --git a/frontend/components/ManageStakingPage/StakingContract/index.tsx b/frontend/components/ManageStakingPage/StakingContract/index.tsx index 230ba6689..fdc8b4c2c 100644 --- a/frontend/components/ManageStakingPage/StakingContract/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContract/index.tsx @@ -6,6 +6,7 @@ import { CardSection } from '@/components/styled/CardSection'; import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { StakingProgram } from '@/enums/StakingProgram'; +import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; import { useBalance } from '@/hooks/useBalance'; import { useStakingContractInfo } from '@/hooks/useStakingContractInfo'; import { useStakingProgram } from '@/hooks/useStakingProgram'; @@ -50,7 +51,7 @@ export const StakingContractSection = ({ stakingProgram: StakingProgram; contractAddress: Address; }) => { - const { activeStakingProgram } = useStakingProgram(); + const { activeStakingProgram, defaultStakingProgram } = useStakingProgram(); const { stakingContractInfoRecord } = useStakingContractInfo(); const { token } = useToken(); const { totalOlasBalance, isBalanceLoaded } = useBalance(); @@ -80,6 +81,7 @@ export const StakingContractSection = ({ const isMigratable = !isSelected && + activeStakingProgram === StakingProgram.Alpha && // TODO: make more elegant isBalanceLoaded && hasEnoughSlots && hasEnoughOlas && @@ -112,9 +114,28 @@ export const StakingContractSection = ({ isAppVersionCompatible, ]); + const contractTagStatus = useMemo(() => { + if (activeStakingProgram === stakingProgram) + return StakingProgramStatus.Selected; + + // Pearl is not staked, set as Selected if default (Beta) + if (!activeStakingProgram && stakingProgram === defaultStakingProgram) + return StakingProgramStatus.Selected; + + // Otherwise, highlight Beta as New + if (stakingProgram === StakingProgram.Beta) return StakingProgramStatus.New; + + // Otherwise, no tag + return; + }, [activeStakingProgram, defaultStakingProgram, stakingProgram]); + return ( {`${activeStakingProgramMeta.name} contract`} {/* TODO: pass `status` attribute */} - + {!isSelected && ( // here instead of isSelected we should check that the contract is not the old staking contract // but the one from staking factory (if we want to open govern) diff --git a/frontend/components/SettingsPage/DebugInfoSection.tsx b/frontend/components/SettingsPage/DebugInfoSection.tsx index cadeda89d..4fa00aebf 100644 --- a/frontend/components/SettingsPage/DebugInfoSection.tsx +++ b/frontend/components/SettingsPage/DebugInfoSection.tsx @@ -13,6 +13,7 @@ import { import { useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; +import { CHAINS } from '@/constants/chains'; import { COLOR } from '@/constants/colors'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { Token } from '@/enums/Token'; @@ -169,16 +170,19 @@ export const DebugInfoSection = () => { }); } - if (services[0]?.chain_data?.instances?.[0]) { - const instanceAddress = services[0].chain_data.instances[0]; + const instanceAddress = + services[0]?.chain_configs?.[CHAINS.GNOSIS.chainId]?.chain_data + ?.instances?.[0]; + if (instanceAddress) { result.push({ title: 'Agent instance', - ...getItemData(walletBalances, instanceAddress), + ...getItemData(walletBalances, instanceAddress!), }); } - if (services[0]?.chain_data?.multisig) { - const multisigAddress = services[0].chain_data.multisig; + const multisigAddress = + services[0]?.chain_configs?.[CHAINS.GNOSIS.chainId]?.chain_data?.multisig; + if (multisigAddress) { result.push({ title: 'Agent Safe', ...getItemData(walletBalances, multisigAddress), diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 32fb9b435..b03851eac 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -1,4 +1,5 @@ import { ServiceTemplate } from '@/client'; +import { StakingProgram } from '@/enums/StakingProgram'; export const SERVICE_TEMPLATES: ServiceTemplate[] = [ { @@ -10,13 +11,13 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ service_version: 'v0.18.1', home_chain_id: '100', configurations: { - '100': { + 100: { + staking_program_id: StakingProgram.Beta, // default, may be overwritten nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', agent_id: 14, threshold: 1, use_staking: true, cost_of_bond: 10000000000000000, - olas_required_to_stake: 10000000000000000000, monthly_gas_estimate: 10000000000000000000, fund_requirements: { agent: 100000000000000000, diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 12c5400ec..cc417462a 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -15,6 +15,7 @@ import { import { useInterval } from 'usehooks-ts'; import { Wallet } from '@/client'; +import { CHAINS } from '@/constants/chains'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { TOKENS } from '@/constants/tokens'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; @@ -134,7 +135,8 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { setWalletBalances(walletBalances); - const serviceId = services?.[0]?.chain_data.token; + const serviceId = + services?.[0]?.chain_configs[CHAINS.GNOSIS.chainId].chain_data.token; if (!isNumber(serviceId)) { setIsLoaded(true); diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index 8b44e2612..a96b43635 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -12,6 +12,7 @@ import { import { useInterval } from 'usehooks-ts'; import { DeploymentStatus, Service } from '@/client'; +import { CHAINS } from '@/constants/chains'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { ServicesService } from '@/service/Services'; import { Address } from '@/types/Address'; @@ -58,11 +59,16 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { const serviceAddresses = useMemo( () => services?.reduce((acc, service: Service) => { - if (service.chain_data.instances) { - acc.push(...service.chain_data.instances); + const instances = + service.chain_configs[CHAINS.GNOSIS.chainId].chain_data.instances; + if (instances) { + acc.push(...instances); } - if (service.chain_data.multisig) { - acc.push(service.chain_data.multisig); + + const multisig = + service.chain_configs[CHAINS.GNOSIS.chainId].chain_data.multisig; + if (multisig) { + acc.push(multisig); } return acc; }, []), diff --git a/frontend/service/Services.ts b/frontend/service/Services.ts index a12591909..44730835c 100644 --- a/frontend/service/Services.ts +++ b/frontend/service/Services.ts @@ -1,5 +1,6 @@ import { Deployment, Service, ServiceHash, ServiceTemplate } from '@/client'; import { BACKEND_URL } from '@/constants/urls'; +import { StakingProgram } from '@/enums/StakingProgram'; /** * Get a single service from the backend @@ -29,11 +30,13 @@ const getServices = async (): Promise => * @returns Promise */ const createService = async ({ - serviceTemplate, deploy, + serviceTemplate, + stakingProgram, }: { - serviceTemplate: ServiceTemplate; deploy: boolean; + serviceTemplate: ServiceTemplate; + stakingProgram: StakingProgram; }): Promise => new Promise((resolve, reject) => fetch(`${BACKEND_URL}/services`, { @@ -41,9 +44,12 @@ const createService = async ({ body: JSON.stringify({ ...serviceTemplate, deploy, - configuration: { - ...serviceTemplate.configuration, - rpc: `${process.env.GNOSIS_RPC}`, + configurations: { + 100: { + ...serviceTemplate.configurations[100], + staking_program_id: stakingProgram, + rpc: `${process.env.GNOSIS_RPC}`, + }, }, }), headers: { diff --git a/frontend/utils/service.ts b/frontend/utils/service.ts index b03820ff2..5d69e2e2f 100644 --- a/frontend/utils/service.ts +++ b/frontend/utils/service.ts @@ -12,12 +12,6 @@ export const getMinimumStakedAmountRequired = ( 18, ), ); - const olasRequiredToStake = Number( - formatUnits( - `${serviceTemplate.configurations[CHAINS.GNOSIS.chainId].olas_required_to_stake}`, - 18, - ), - ); - return olasCostOfBond + olasRequiredToStake; + return olasCostOfBond * 2; }; From 4c9fefa95ee2331b70340ff9555a237e31325e8d Mon Sep 17 00:00:00 2001 From: Ardian Date: Fri, 16 Aug 2024 17:24:30 +0200 Subject: [PATCH 70/99] fix: local deployment --- operate/cli.py | 1 + operate/services/service.py | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index 86acd8031..7d5285d13 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -647,6 +647,7 @@ async def _get_service_deployment(request: Request) -> JSONResponse: @with_retries async def _build_service_locally(request: Request) -> JSONResponse: """Create a service.""" + # TODO: add support for chain id. if not operate.service_manager().exists(service=request.path_params["service"]): return service_not_found_error(service=request.path_params["service"]) deployment = ( diff --git a/operate/services/service.py b/operate/services/service.py index 5ecabf103..6a476866b 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -484,7 +484,7 @@ def _build_docker( self.status = DeploymentStatus.BUILT self.store() - def _build_host(self, force: bool = True) -> None: + def _build_host(self, force: bool = True, chain_id: str = "100") -> None: """Build host depployment.""" build = self.path / DEPLOYMENT if build.exists() and not force: @@ -500,6 +500,10 @@ def _build_host(self, force: bool = True) -> None: "Host deployment currently only supports single agent deployments" ) + chain_config = service.chain_configs[chain_id] + ledger_config = chain_config.ledger_config + chain_data = chain_config.chain_data + keys_file = self.path / KEYS_JSON keys_file.write_text( json.dumps( @@ -524,15 +528,15 @@ def _build_host(self, force: bool = True) -> None: builder.deplopyment_type = HostDeploymentGenerator.deployment_type builder.try_update_abci_connection_params() builder.try_update_runtime_params( - multisig_address=service.chain_data.multisig, - agent_instances=service.chain_data.instances, - service_id=service.chain_data.token, + multisig_address=chain_data.multisig, + agent_instances=chain_data.instances, + service_id=chain_data.token, consensus_threshold=None, ) # TODO: Support for multiledger builder.try_update_ledger_params( - chain=LedgerType(service.ledger_config.type).name.lower(), - address=service.ledger_config.rpc, + chain=LedgerType(ledger_config.type).name.lower(), + address=ledger_config.rpc, ) ( @@ -569,6 +573,7 @@ def build( self, use_docker: bool = False, force: bool = True, + chain_id: str = "100", ) -> None: """ Build a deployment @@ -577,9 +582,10 @@ def build( :param force: Remove existing deployment and build a new one :return: Deployment object """ + # TODO: chain_id should be used properly! Added as a hotfix for now. if use_docker: return self._build_docker(force=force) - return self._build_host(force=force) + return self._build_host(force=force, chain_id=chain_id) def start(self, use_docker: bool = False) -> None: """Start the service""" From de443c37abe4aeaf5eec0588cb243a793fcb4d56 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 19:38:32 +0100 Subject: [PATCH 71/99] refactor: remove migrating button, reset create service null coalesce --- .../MainPage/header/AgentButton.tsx | 20 +-- .../StakingContractTag.tsx | 0 .../alerts.tsx | 0 .../index.tsx | 125 ++++++++++++++++-- .../components/ManageStakingPage/index.tsx | 21 +-- ...tsx => SettingsStakingContractSection.tsx} | 21 ++- frontend/components/SettingsPage/index.tsx | 4 +- frontend/constants/serviceTemplates.ts | 1 + frontend/context/ModalProvider.tsx | 33 +++++ frontend/context/RewardProvider.tsx | 18 ++- .../context/StakingContractInfoProvider.tsx | 6 +- frontend/context/StakingProgramContext.tsx | 27 ++-- frontend/hooks/useModals.ts | 12 +- frontend/hooks/useStakingContractInfo.ts | 1 + frontend/hooks/useStakingProgram.ts | 27 ++-- frontend/pages/_app.tsx | 13 +- frontend/service/Autonolas.ts | 15 ++- operate/cli.py | 1 - 18 files changed, 236 insertions(+), 109 deletions(-) rename frontend/components/ManageStakingPage/{StakingContract => StakingContractSection}/StakingContractTag.tsx (100%) rename frontend/components/ManageStakingPage/{StakingContract => StakingContractSection}/alerts.tsx (100%) rename frontend/components/ManageStakingPage/{StakingContract => StakingContractSection}/index.tsx (58%) rename frontend/components/SettingsPage/{StakingContractSection.tsx => SettingsStakingContractSection.tsx} (70%) create mode 100644 frontend/context/ModalProvider.tsx diff --git a/frontend/components/MainPage/header/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton.tsx index 3db3f053b..c58cdd3b9 100644 --- a/frontend/components/MainPage/header/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton.tsx @@ -151,12 +151,11 @@ const AgentNotRunningButton = () => { // Then create / deploy the service try { await ServicesService.createService({ - stakingProgram: activeStakingProgram ?? defaultStakingProgram, + stakingProgram: activeStakingProgram ?? defaultStakingProgram, // overwrite with StakingProgram.Alpha to test migration serviceTemplate, deploy: true, }); } catch (error) { - 0; console.error(error); setServiceStatus(undefined); showNotification?.('Error while deploying service'); @@ -254,19 +253,7 @@ const AgentNotRunningButton = () => { return ; }; -const MigratingButton = () => { - return ( - - - - ); -}; - export const AgentButton = () => { - const { isMigrating } = useStakingProgram(); const { service, serviceStatus, hasInitialLoaded } = useServices(); const { isEligibleForStaking, isAgentEvicted } = useStakingContractInfo(); @@ -275,10 +262,6 @@ export const AgentButton = () => { return + + + )} ); diff --git a/frontend/components/ManageStakingPage/index.tsx b/frontend/components/ManageStakingPage/index.tsx index 45ed4f2d2..310d19eca 100644 --- a/frontend/components/ManageStakingPage/index.tsx +++ b/frontend/components/ManageStakingPage/index.tsx @@ -8,28 +8,9 @@ import { StakingProgram } from '@/enums/StakingProgram'; import { usePageState } from '@/hooks/usePageState'; import { CardTitle } from '../Card/CardTitle'; -import { StakingContractSection } from './StakingContract'; +import { StakingContractSection } from './StakingContractSection'; import { WhatAreStakingContractsSection } from './WhatAreStakingContracts'; -// const mockStakingContracts: StakingProgram[] = [ -// { -// name: 'Pearl Beta', -// rewardsPerWorkPeriod: 0.14, -// requiredOlasForStaking: 40, -// isEnoughSlots: true, -// status: StakingProgramStatus.New, -// contractAddress: '0x1234567890', -// }, -// { -// name: 'Pearl Alpha', -// rewardsPerWorkPeriod: 0.047, -// requiredOlasForStaking: 20, -// isEnoughSlots: true, -// status: StakingProgramStatus.Selected, -// contractAddress: '0x0987654321', -// }, -// ]; - export const ManageStakingPage = () => { const { goto } = usePageState(); return ( diff --git a/frontend/components/SettingsPage/StakingContractSection.tsx b/frontend/components/SettingsPage/SettingsStakingContractSection.tsx similarity index 70% rename from frontend/components/SettingsPage/StakingContractSection.tsx rename to frontend/components/SettingsPage/SettingsStakingContractSection.tsx index d1e9c6a3f..121b36476 100644 --- a/frontend/components/SettingsPage/StakingContractSection.tsx +++ b/frontend/components/SettingsPage/SettingsStakingContractSection.tsx @@ -1,4 +1,4 @@ -import { Button, Flex, Typography } from 'antd'; +import { Button, Flex, Skeleton, Typography } from 'antd'; import { Chain } from '@/client'; import { SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES } from '@/constants/contractAddresses'; @@ -11,24 +11,33 @@ import { CardSection } from '../styled/CardSection'; const { Text } = Typography; -export const StakingContractSection = () => { +export const SettingsStakingContractSection = () => { const { goto } = usePageState(); const { - activeStakingProgram: currentStakingProgram, - activeStakingProgramMeta: currentStakingProgramMeta, + activeStakingProgram, + activeStakingProgramMeta, defaultStakingProgram, + isLoadedActiveStakingProgram, } = useStakingProgram(); const stakingContractAddress = SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS][ - currentStakingProgram ?? defaultStakingProgram + activeStakingProgram ?? defaultStakingProgram ]; + if (!isLoadedActiveStakingProgram) { + return ; + } + return ( Staking contract - {currentStakingProgramMeta.name} + + {activeStakingProgramMeta + ? activeStakingProgramMeta.name + : 'Not staked'} + { )} {/* Staking contract section */} - + {/* Debug info */} diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index b03851eac..dcb2fd1aa 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -5,6 +5,7 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ { name: 'Trader Agent', hash: 'bafybeidgjgjj5ul6xkubicbemppufgsbx5sr5rwhtrwttk2oivp5bkdnce', + // hash: 'bafybeibbloa4w33vj4bvdkso7pzk6tr3duvxjpecbx4mur4ix6ehnwb5uu', // temporary description: 'Trader agent for omen prediction markets', image: 'https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75', diff --git a/frontend/context/ModalProvider.tsx b/frontend/context/ModalProvider.tsx new file mode 100644 index 000000000..90768cce4 --- /dev/null +++ b/frontend/context/ModalProvider.tsx @@ -0,0 +1,33 @@ +import { + createContext, + Dispatch, + PropsWithChildren, + SetStateAction, + useState, +} from 'react'; + +import { MigrationSuccessModal } from '@/components/MainPage/modals/MigrationModal'; + +export const ModalContext = createContext<{ + migrationModalOpen: boolean; + setMigrationModalOpen: Dispatch>; +}>({ + migrationModalOpen: false, + setMigrationModalOpen: () => {}, +}); + +export const ModalProvider = ({ children }: PropsWithChildren) => { + const [migrationModalOpen, setMigrationModalOpen] = useState(false); + + return ( + + setMigrationModalOpen(false)} + /> + {children} + + ); +}; diff --git a/frontend/context/RewardProvider.tsx b/frontend/context/RewardProvider.tsx index 589db9d6a..b5b5480c0 100644 --- a/frontend/context/RewardProvider.tsx +++ b/frontend/context/RewardProvider.tsx @@ -10,6 +10,7 @@ import { } from 'react'; import { useInterval } from 'usehooks-ts'; +import { CHAINS } from '@/constants/chains'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useStore } from '@/hooks/useStore'; @@ -76,12 +77,14 @@ export const RewardProvider = ({ children }: PropsWithChildren) => { // only check for rewards if there's a currentStakingProgram active if ( activeStakingProgram && - service?.chain_data?.multisig && - service?.chain_data?.token + service?.chain_configs[CHAINS.GNOSIS.chainId].chain_data?.multisig && + service?.chain_configs[CHAINS.GNOSIS.chainId].chain_data?.token ) { stakingRewardsInfoPromise = AutonolasService.getAgentStakingRewardsInfo({ - agentMultisigAddress: service?.chain_data?.multisig, - serviceId: service?.chain_data?.token, + agentMultisigAddress: + service.chain_configs[CHAINS.GNOSIS.chainId].chain_data.multisig!, + serviceId: + service.chain_configs[CHAINS.GNOSIS.chainId].chain_data.token!, stakingProgram: activeStakingProgram, }); } @@ -101,12 +104,7 @@ export const RewardProvider = ({ children }: PropsWithChildren) => { stakingRewardsInfo?.accruedServiceStakingRewards, ); setAvailableRewardsForEpoch(rewards); - }, [ - activeStakingProgram, - defaultStakingProgram, - service?.chain_data?.multisig, - service?.chain_data?.token, - ]); + }, [activeStakingProgram, defaultStakingProgram, service]); useEffect(() => { if (isEligibleForRewards && !storeState?.firstStakingRewardAchieved) { diff --git a/frontend/context/StakingContractInfoProvider.tsx b/frontend/context/StakingContractInfoProvider.tsx index 10ba73ede..6bf19408a 100644 --- a/frontend/context/StakingContractInfoProvider.tsx +++ b/frontend/context/StakingContractInfoProvider.tsx @@ -9,6 +9,7 @@ import { } from 'react'; import { useInterval } from 'usehooks-ts'; +import { CHAINS } from '@/constants/chains'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { StakingProgram } from '@/enums/StakingProgram'; import { AutonolasService } from '@/service/Autonolas'; @@ -45,7 +46,10 @@ export const StakingContractInfoProvider = ({ const [stakingContractInfoRecord, setStakingContractInfoRecord] = useState>>(); - const serviceId = useMemo(() => services?.[0]?.chain_data?.token, [services]); + const serviceId = useMemo( + () => services?.[0]?.chain_configs[CHAINS.GNOSIS.chainId].chain_data?.token, + [services], + ); // ACTIVE staking contract info should be updated on interval // it requires serviceId and activeStakingProgram diff --git a/frontend/context/StakingProgramContext.tsx b/frontend/context/StakingProgramContext.tsx index 386c20b5d..420ef5bcf 100644 --- a/frontend/context/StakingProgramContext.tsx +++ b/frontend/context/StakingProgramContext.tsx @@ -1,5 +1,7 @@ import { createContext, PropsWithChildren, useCallback, useState } from 'react'; +import { useInterval } from 'usehooks-ts'; +import { CHAINS } from '@/constants/chains'; import { StakingProgram } from '@/enums/StakingProgram'; import { useServices } from '@/hooks/useServices'; import { AutonolasService } from '@/service/Autonolas'; @@ -18,26 +20,33 @@ export const StakingProgramContext = createContext<{ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { const { service } = useServices(); - const [activeStakingProgram, setCurrentStakingProgram] = + const [activeStakingProgram, setActiveStakingProgram] = useState(); const updateStakingProgram = useCallback(async () => { - // if no service / instance is available, we don't need to check for staking program - if (!service?.chain_data?.instances?.[0]) { - setCurrentStakingProgram(null); + // if no service nft, not staked + const serviceId = + service?.chain_configs[CHAINS.GNOSIS.chainId].chain_data?.token; + + if (!service?.chain_configs[CHAINS.GNOSIS.chainId].chain_data?.token) { + setActiveStakingProgram(null); return; } - // TODO: check if assuming the first service is the correct approach - const operatorAddress = service?.chain_data?.instances?.[0]; - if (operatorAddress) { + if (serviceId) { // if service exists, we need to check if it is staked - AutonolasService.getCurrentStakingProgram(operatorAddress).then( - setCurrentStakingProgram, + console.log('getting current staking program'); + AutonolasService.getCurrentStakingProgramByServiceId(serviceId).then( + (stakingProgram) => { + console.log('setting stakingProgram', stakingProgram); + setActiveStakingProgram(stakingProgram); + }, ); } }, [service]); + useInterval(updateStakingProgram, 5000); + return ( { - const [isMigrationSuccessModalOpen, setIsMigrationSuccessModalOpen] = - useState(false); + const { migrationModalOpen, setMigrationModalOpen } = + useContext(ModalContext); return { - isMigrationSuccessModalOpen, - setIsMigrationSuccessModalOpen, + migrationModalOpen, + setMigrationModalOpen, }; }; diff --git a/frontend/hooks/useStakingContractInfo.ts b/frontend/hooks/useStakingContractInfo.ts index 74fdc517a..089183260 100644 --- a/frontend/hooks/useStakingContractInfo.ts +++ b/frontend/hooks/useStakingContractInfo.ts @@ -60,5 +60,6 @@ export const useStakingContractInfo = () => { isRewardsAvailable, isAgentEvicted, stakingContractInfoRecord, + isServiceStakedForMinimumDuration, }; }; diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index af04920ed..585bcab49 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -1,4 +1,4 @@ -import { useContext, useState } from 'react'; +import { useContext } from 'react'; import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; import { StakingProgramContext } from '@/context/StakingProgramContext'; @@ -8,28 +8,23 @@ import { StakingProgramContext } from '@/context/StakingProgramContext'; * @returns {currentStakingProgram: IncentiveProgram} */ export const useStakingProgram = () => { - const { activeStakingProgram, defaultStakingProgram } = useContext( - StakingProgramContext, - ); + const { activeStakingProgram, defaultStakingProgram, updateStakingProgram } = + useContext(StakingProgramContext); - const [isMigrating, setIsMigrating] = useState(false); + const isLoadedActiveStakingProgram = activeStakingProgram !== undefined; const activeStakingProgramMeta = - STAKING_PROGRAM_META[activeStakingProgram ?? defaultStakingProgram]; - - // TODO: Implement migration logic - const migrate = async () => { - setIsMigrating(true); - await setTimeout(() => { - setIsMigrating(false); - }, 1000); - }; + activeStakingProgram === undefined + ? null + : activeStakingProgram === null + ? null + : STAKING_PROGRAM_META[activeStakingProgram]; return { activeStakingProgram, activeStakingProgramMeta, defaultStakingProgram, - isMigrating, - migrate, + updateStakingProgram, + isLoadedActiveStakingProgram, }; }; diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 94e588e6d..42657f818 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -8,6 +8,7 @@ import { Layout } from '@/components/Layout'; import { BalanceProvider } from '@/context/BalanceProvider'; import { ElectronApiProvider } from '@/context/ElectronApiProvider'; import { MasterSafeProvider } from '@/context/MasterSafeProvider'; +import { ModalProvider } from '@/context/ModalProvider'; import { OnlineStatusProvider } from '@/context/OnlineStatusProvider'; import { PageStateProvider } from '@/context/PageStateProvider'; import { RewardProvider } from '@/context/RewardProvider'; @@ -41,11 +42,13 @@ export default function App({ Component, pageProps }: AppProps) { - {isMounted ? ( - - - - ) : null} + + {isMounted ? ( + + + + ) : null} + diff --git a/frontend/service/Autonolas.ts b/frontend/service/Autonolas.ts index 190fc6030..0b11573df 100644 --- a/frontend/service/Autonolas.ts +++ b/frontend/service/Autonolas.ts @@ -89,6 +89,7 @@ const getAgentStakingRewardsInfo = async ({ ].calculateStakingReward(serviceId), serviceStakingTokenMechUsageContracts[stakingProgram].minStakingDeposit(), serviceStakingTokenMechUsageContracts[stakingProgram].tsCheckpoint(), + serviceStakingTokenMechUsageContracts[stakingProgram].minStakingDuration(), ]; await gnosisMulticallProvider.init(); @@ -104,6 +105,7 @@ const getAgentStakingRewardsInfo = async ({ accruedStakingReward, minStakingDeposit, tsCheckpoint, + minStakingDuration, ] = multicallResponse; /** @@ -308,15 +310,15 @@ const getServiceRegistryInfo = async ( }; }; -const getCurrentStakingProgram = async ( - agentAddress: string, +const getCurrentStakingProgramByServiceId = async ( + serviceId: number, ): Promise => { const contractCalls = [ serviceStakingTokenMechUsageContracts[StakingProgram.Alpha].getStakingState( - agentAddress, + serviceId, ), serviceStakingTokenMechUsageContracts[StakingProgram.Beta].getStakingState( - agentAddress, + serviceId, ), ]; @@ -326,6 +328,8 @@ const getCurrentStakingProgram = async ( const [isAlphaStaked, isBetaStaked] = await gnosisMulticallProvider.all(contractCalls); + console.log(isAlphaStaked, isBetaStaked); + // Alpha should take precedence, as it must be migrated from return isAlphaStaked ? StakingProgram.Alpha @@ -333,6 +337,7 @@ const getCurrentStakingProgram = async ( ? StakingProgram.Beta : null; } catch (error) { + console.log('Error while getting current staking program', error); return null; } }; @@ -340,7 +345,7 @@ const getCurrentStakingProgram = async ( export const AutonolasService = { getAgentStakingRewardsInfo, getAvailableRewardsForEpoch, - getCurrentStakingProgram, + getCurrentStakingProgramByServiceId, getServiceRegistryInfo, getStakingContractInfoByServiceIdStakingProgram, getStakingContractInfoByStakingProgram, diff --git a/operate/cli.py b/operate/cli.py index 7d5285d13..1eac6a3b6 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -528,7 +528,6 @@ async def _create_services(request: Request) -> JSONResponse: ) if template.get("deploy", False): - def _fn() -> None: manager.deploy_service_onchain_from_safe(hash=service.hash) # manager.stake_service_on_chain_from_safe(hash=service.hash) # Done inside deploy_service_onchain From 8fe5fa38d36a9aecebcc3e74f80811595c5fdb51 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 19:40:17 +0100 Subject: [PATCH 72/99] refactor: improve staking program retrieval and error handling --- frontend/context/StakingProgramContext.tsx | 2 -- frontend/service/Autonolas.ts | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/frontend/context/StakingProgramContext.tsx b/frontend/context/StakingProgramContext.tsx index 420ef5bcf..290f1d607 100644 --- a/frontend/context/StakingProgramContext.tsx +++ b/frontend/context/StakingProgramContext.tsx @@ -35,10 +35,8 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { if (serviceId) { // if service exists, we need to check if it is staked - console.log('getting current staking program'); AutonolasService.getCurrentStakingProgramByServiceId(serviceId).then( (stakingProgram) => { - console.log('setting stakingProgram', stakingProgram); setActiveStakingProgram(stakingProgram); }, ); diff --git a/frontend/service/Autonolas.ts b/frontend/service/Autonolas.ts index 0b11573df..2a6b9c3fb 100644 --- a/frontend/service/Autonolas.ts +++ b/frontend/service/Autonolas.ts @@ -328,8 +328,6 @@ const getCurrentStakingProgramByServiceId = async ( const [isAlphaStaked, isBetaStaked] = await gnosisMulticallProvider.all(contractCalls); - console.log(isAlphaStaked, isBetaStaked); - // Alpha should take precedence, as it must be migrated from return isAlphaStaked ? StakingProgram.Alpha @@ -337,7 +335,7 @@ const getCurrentStakingProgramByServiceId = async ( ? StakingProgram.Beta : null; } catch (error) { - console.log('Error while getting current staking program', error); + console.error('Error while getting current staking program', error); return null; } }; From d9b29b37f2b39eb25931e3fb1451ae6709c6f2d0 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 19:41:54 +0100 Subject: [PATCH 73/99] refactor: remove unused code in StakingContractSection --- .../StakingContractSection/index.tsx | 45 +++++++++---------- frontend/service/Autonolas.ts | 2 - 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index 53fd4901a..b07f07749 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -1,6 +1,5 @@ -import { Button, Divider, Flex, Popover, theme, Typography } from 'antd'; +import { Button, Flex, Popover, theme, Typography } from 'antd'; import { useMemo } from 'react'; -import styled from 'styled-components'; import { DeploymentStatus } from '@/client'; import { CardSection } from '@/components/styled/CardSection'; @@ -26,30 +25,30 @@ import { } from './alerts'; import { StakingContractTag } from './StakingContractTag'; -const { Text } = Typography; +// const { Text } = Typography; const { useToken } = theme; -const CustomDivider = styled(Divider)` - flex: auto; - width: max-content; - min-width: 0; - margin: 0; -`; - -const ContractParameter = ({ - label, - value, -}: { - label: string; - value: string; -}) => ( - - {label} - - {value} - -); +// const CustomDivider = styled(Divider)` +// flex: auto; +// width: max-content; +// min-width: 0; +// margin: 0; +// `; + +// const ContractParameter = ({ +// label, +// value, +// }: { +// label: string; +// value: string; +// }) => ( +// +// {label} +// +// {value} +// +// ); export const StakingContractSection = ({ stakingProgram, diff --git a/frontend/service/Autonolas.ts b/frontend/service/Autonolas.ts index 2a6b9c3fb..b0e9e74d6 100644 --- a/frontend/service/Autonolas.ts +++ b/frontend/service/Autonolas.ts @@ -89,7 +89,6 @@ const getAgentStakingRewardsInfo = async ({ ].calculateStakingReward(serviceId), serviceStakingTokenMechUsageContracts[stakingProgram].minStakingDeposit(), serviceStakingTokenMechUsageContracts[stakingProgram].tsCheckpoint(), - serviceStakingTokenMechUsageContracts[stakingProgram].minStakingDuration(), ]; await gnosisMulticallProvider.init(); @@ -105,7 +104,6 @@ const getAgentStakingRewardsInfo = async ({ accruedStakingReward, minStakingDeposit, tsCheckpoint, - minStakingDuration, ] = multicallResponse; /** From e56fa4e0133799a15c3a0b4f7308a2a56853fde4 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 19:43:32 +0100 Subject: [PATCH 74/99] bump: 112 --- electron/install.js | 2 +- package.json | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/electron/install.js b/electron/install.js index 23cda3da0..7988e07fa 100644 --- a/electron/install.js +++ b/electron/install.js @@ -14,7 +14,7 @@ const { paths } = require('./constants'); * - use "" (nothing as a suffix) for latest release candidate, for example "0.1.0rc26" * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ -const OlasMiddlewareVersion = '0.1.0rc110'; +const OlasMiddlewareVersion = '0.1.0rc112'; const path = require('path'); const { app } = require('electron'); diff --git a/package.json b/package.json index a813f31fc..857c15b20 100644 --- a/package.json +++ b/package.json @@ -59,5 +59,5 @@ "build:pearl": "sh build_pearl.sh" }, - "version": "0.1.0-rc110" + "version": "0.1.0-rc112" } diff --git a/pyproject.toml b/pyproject.toml index ee2657faf..b77f08413 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc110" +version = "0.1.0-rc112" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From 9d70c41b69110e0a25e27386cbd585d3061194dc Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 19:48:46 +0100 Subject: [PATCH 75/99] fix: release.yml service_version --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 044325707..a07e5fe40 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,7 +44,7 @@ jobs: - name: Get trader bin run: | - trader_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/trader.yaml')); print(config['trader_version'])") + trader_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/trader.yaml')); print(config['service_version'])") echo $trader_version mkdir dist && curl -L -o dist/aea_bin "https://github.com/valory-xyz/trader/releases/download/${trader_version}/trader_bin_${{ env.OS_ARCH }}" From 9f2ed5b10501e6530d749d88df8dcff8ae8d4f65 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 19:54:41 +0100 Subject: [PATCH 76/99] refactor: update chain data types --- frontend/hooks/useServices.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/hooks/useServices.ts b/frontend/hooks/useServices.ts index 595dca84c..3fa3cfda7 100644 --- a/frontend/hooks/useServices.ts +++ b/frontend/hooks/useServices.ts @@ -13,7 +13,11 @@ const checkServiceIsFunded = async ( serviceTemplate: ServiceTemplate, ): Promise => { const { - chain_data: { instances, multisig }, + chain_configs: { + [CHAINS.GNOSIS.chainId]: { + chain_data: { instances, multisig }, + }, + }, } = service; if (!instances || !multisig) return false; From e66dedae2ac6afb380f1ddd32ac23cf6a0926ee3 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 21:08:18 +0100 Subject: [PATCH 77/99] fix: dynamic olas requirement dependant on staking program --- .../MainPage/header/AgentButton.tsx | 22 ++++++++++------- .../StakingContractSection/index.tsx | 24 +++++++++++-------- frontend/context/StakingProgramContext.tsx | 10 ++++---- frontend/hooks/useStakingProgram.ts | 7 ++++-- frontend/utils/service.ts | 24 +++++++++++-------- 5 files changed, 52 insertions(+), 35 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton.tsx index c58cdd3b9..4bd0e0a17 100644 --- a/frontend/components/MainPage/header/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton.tsx @@ -5,6 +5,7 @@ import { useCallback, useMemo } from 'react'; import { Chain, DeploymentStatus } from '@/client'; import { COLOR } from '@/constants/colors'; import { LOW_BALANCE } from '@/constants/thresholds'; +import { StakingProgram } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useServices } from '@/hooks/useServices'; @@ -106,14 +107,17 @@ const AgentNotRunningButton = () => { totalEthBalance, } = useBalance(); const { storeState } = useStore(); - const { isEligibleForStaking, isAgentEvicted, stakingContractInfoRecord } = - useStakingContractInfo(); + const { isEligibleForStaking, isAgentEvicted } = useStakingContractInfo(); const { activeStakingProgram, defaultStakingProgram } = useStakingProgram(); - const minStakingDeposit = - stakingContractInfoRecord?.[activeStakingProgram ?? defaultStakingProgram] - ?.minStakingDeposit; - const requiredOlas = minStakingDeposit && minStakingDeposit * 2; + // const minStakingDeposit = + // stakingContractInfoRecord?.[activeStakingProgram ?? defaultStakingProgram] + // ?.minStakingDeposit; + + const requiredOlas = getMinimumStakedAmountRequired( + serviceTemplate, + activeStakingProgram ?? defaultStakingProgram, + ); const safeOlasBalance = safeBalance?.OLAS; const safeOlasBalanceWithStaked = @@ -169,8 +173,10 @@ const AgentNotRunningButton = () => { if (!service) { showNotification?.('Your agent is now running!'); } else { - const minimumStakedAmountRequired = - getMinimumStakedAmountRequired(serviceTemplate); + const minimumStakedAmountRequired = getMinimumStakedAmountRequired( + serviceTemplate, + StakingProgram.Beta, // users should always deploy on Beta if they are yet to start their agent + ); showNotification?.( `Your agent is running and you've staked ${minimumStakedAmountRequired} OLAS!`, diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index b07f07749..227cb6758 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -69,27 +69,31 @@ export const StakingContractSection = ({ const { totalOlasBalance, isBalanceLoaded } = useBalance(); const { isServiceStakedForMinimumDuration } = useStakingContractInfo(); - const stakingContractInfo = stakingContractInfoRecord?.[stakingProgram]; + const stakingContractInfoForStakingProgram = + stakingContractInfoRecord?.[stakingProgram]; const activeStakingProgramMeta = STAKING_PROGRAM_META[stakingProgram]; const isSelected = activeStakingProgram && activeStakingProgram === stakingProgram; - const hasEnoughRewards = (stakingContractInfo?.availableRewards ?? 0) > 0; + const hasEnoughRewards = + (stakingContractInfoForStakingProgram?.availableRewards ?? 0) > 0; const hasEnoughOlasToMigrate = useMemo(() => { if (totalOlasBalance === undefined) return false; - if (!stakingContractInfo) return false; - if (!stakingContractInfo.minStakingDeposit) return false; - return totalOlasBalance > stakingContractInfo?.minStakingDeposit; - }, [stakingContractInfo, totalOlasBalance]); + if (!stakingContractInfoForStakingProgram) return false; + if (!stakingContractInfoForStakingProgram.minStakingDeposit) return false; + return ( + totalOlasBalance > stakingContractInfoForStakingProgram?.minStakingDeposit + ); + }, [stakingContractInfoForStakingProgram, totalOlasBalance]); const hasEnoughSlots = - stakingContractInfo?.maxNumServices && - stakingContractInfo?.serviceIds && - stakingContractInfo?.maxNumServices > - stakingContractInfo?.serviceIds?.length; + stakingContractInfoForStakingProgram?.maxNumServices && + stakingContractInfoForStakingProgram?.serviceIds && + stakingContractInfoForStakingProgram?.maxNumServices > + stakingContractInfoForStakingProgram?.serviceIds?.length; // TODO: compatibility needs to be implemented const isAppVersionCompatible = true; // contract.appVersion === 'rc105'; diff --git a/frontend/context/StakingProgramContext.tsx b/frontend/context/StakingProgramContext.tsx index 290f1d607..fecdf645c 100644 --- a/frontend/context/StakingProgramContext.tsx +++ b/frontend/context/StakingProgramContext.tsx @@ -9,11 +9,11 @@ import { AutonolasService } from '@/service/Autonolas'; export const StakingProgramContext = createContext<{ activeStakingProgram?: StakingProgram | null; defaultStakingProgram: StakingProgram; - updateStakingProgram: () => Promise; + updateActiveStakingProgram: () => Promise; }>({ activeStakingProgram: undefined, defaultStakingProgram: StakingProgram.Beta, - updateStakingProgram: async () => {}, + updateActiveStakingProgram: async () => {}, }); /** Determines the current active staking program, if any */ @@ -23,7 +23,7 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { const [activeStakingProgram, setActiveStakingProgram] = useState(); - const updateStakingProgram = useCallback(async () => { + const updateActiveStakingProgram = useCallback(async () => { // if no service nft, not staked const serviceId = service?.chain_configs[CHAINS.GNOSIS.chainId].chain_data?.token; @@ -43,13 +43,13 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { } }, [service]); - useInterval(updateStakingProgram, 5000); + useInterval(updateActiveStakingProgram, 5000); return ( diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index 585bcab49..8d07739be 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -8,8 +8,11 @@ import { StakingProgramContext } from '@/context/StakingProgramContext'; * @returns {currentStakingProgram: IncentiveProgram} */ export const useStakingProgram = () => { - const { activeStakingProgram, defaultStakingProgram, updateStakingProgram } = - useContext(StakingProgramContext); + const { + activeStakingProgram, + defaultStakingProgram, + updateActiveStakingProgram: updateStakingProgram, + } = useContext(StakingProgramContext); const isLoadedActiveStakingProgram = activeStakingProgram !== undefined; diff --git a/frontend/utils/service.ts b/frontend/utils/service.ts index 5d69e2e2f..5a957ce93 100644 --- a/frontend/utils/service.ts +++ b/frontend/utils/service.ts @@ -1,17 +1,21 @@ -import { formatUnits } from 'ethers/lib/utils'; - import { ServiceTemplate } from '@/client'; -import { CHAINS } from '@/constants/chains'; +import { StakingProgram } from '@/enums/StakingProgram'; +/** TODO: update from hardcoded, workaround for quick release */ export const getMinimumStakedAmountRequired = ( serviceTemplate: ServiceTemplate, + stakingProgram: StakingProgram = StakingProgram.Beta, ) => { - const olasCostOfBond = Number( - formatUnits( - `${serviceTemplate.configurations[CHAINS.GNOSIS.chainId].cost_of_bond}`, - 18, - ), - ); + // const olasCostOfBond = Number( + // formatUnits( + // `${serviceTemplate.configurations[CHAINS.GNOSIS.chainId].cost_of_bond}`, + // 18, + // ), + // ); + + if (stakingProgram === StakingProgram.Alpha) { + return 20; + } - return olasCostOfBond * 2; + return 40; }; From 8680d1bdd34bb45bdcaf6b43439e9da4bfe2c092 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 21:09:53 +0100 Subject: [PATCH 78/99] fix: migration requirement --- .../ManageStakingPage/StakingContractSection/index.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index 227cb6758..4b1e52a0b 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -17,6 +17,7 @@ import { useStakingContractInfo } from '@/hooks/useStakingContractInfo'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { ServicesService } from '@/service/Services'; import { Address } from '@/types/Address'; +import { getMinimumStakedAmountRequired } from '@/utils/service'; import { AlertInsufficientMigrationFunds, @@ -85,9 +86,10 @@ export const StakingContractSection = ({ if (!stakingContractInfoForStakingProgram) return false; if (!stakingContractInfoForStakingProgram.minStakingDeposit) return false; return ( - totalOlasBalance > stakingContractInfoForStakingProgram?.minStakingDeposit + totalOlasBalance >= + getMinimumStakedAmountRequired(serviceTemplate, StakingProgram.Beta) ); - }, [stakingContractInfoForStakingProgram, totalOlasBalance]); + }, [serviceTemplate, stakingContractInfoForStakingProgram, totalOlasBalance]); const hasEnoughSlots = stakingContractInfoForStakingProgram?.maxNumServices && From 43b603c8d4d94b48630356e48f46e71bef440489 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 21:16:42 +0100 Subject: [PATCH 79/99] refactor: update minimum OLAS balance requirement for migration --- .../StakingContractSection/index.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index 4b1e52a0b..d361ee1cb 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -81,15 +81,16 @@ export const StakingContractSection = ({ const hasEnoughRewards = (stakingContractInfoForStakingProgram?.availableRewards ?? 0) > 0; + const minimumOlasRequiredToMigrate = useMemo( + () => getMinimumStakedAmountRequired(serviceTemplate, StakingProgram.Beta), + [serviceTemplate], + ); + const hasEnoughOlasToMigrate = useMemo(() => { if (totalOlasBalance === undefined) return false; - if (!stakingContractInfoForStakingProgram) return false; - if (!stakingContractInfoForStakingProgram.minStakingDeposit) return false; - return ( - totalOlasBalance >= - getMinimumStakedAmountRequired(serviceTemplate, StakingProgram.Beta) - ); - }, [serviceTemplate, stakingContractInfoForStakingProgram, totalOlasBalance]); + if (!minimumOlasRequiredToMigrate) return false; + return totalOlasBalance >= minimumOlasRequiredToMigrate; + }, [minimumOlasRequiredToMigrate, totalOlasBalance]); const hasEnoughSlots = stakingContractInfoForStakingProgram?.maxNumServices && @@ -123,7 +124,7 @@ export const StakingContractSection = ({ } if (activeStakingProgram !== StakingProgram.Alpha) { - return 'Can only migrate from Alpha'; + return 'Can only migrate from Alpha to Beta'; } if (!isBalanceLoaded) { @@ -135,7 +136,7 @@ export const StakingContractSection = ({ } if (!hasEnoughOlasToMigrate) { - return 'Insufficient OLAS balance to migrate'; + return 'Insufficient OLAS balance to migrate, need ${}'; } if (!isAppVersionCompatible) { From 3dfebf55378ab9b498404570a38ed14d7f3b193f Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 21:23:27 +0100 Subject: [PATCH 80/99] refactor: force rewards availability check to true --- .../ManageStakingPage/StakingContractSection/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index d361ee1cb..b8fdf664c 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -78,8 +78,8 @@ export const StakingContractSection = ({ const isSelected = activeStakingProgram && activeStakingProgram === stakingProgram; - const hasEnoughRewards = - (stakingContractInfoForStakingProgram?.availableRewards ?? 0) > 0; + const hasEnoughRewards = true; + //(stakingContractInfoForStakingProgram?.availableRewards ?? 0) > 0; const minimumOlasRequiredToMigrate = useMemo( () => getMinimumStakedAmountRequired(serviceTemplate, StakingProgram.Beta), From 5a27881304e3c4c3528de58a996c7865898f6d40 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 16 Aug 2024 21:24:28 +0100 Subject: [PATCH 81/99] fix: default rewards availiability to true --- frontend/hooks/useStakingContractInfo.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/hooks/useStakingContractInfo.ts b/frontend/hooks/useStakingContractInfo.ts index 089183260..460f74613 100644 --- a/frontend/hooks/useStakingContractInfo.ts +++ b/frontend/hooks/useStakingContractInfo.ts @@ -23,7 +23,7 @@ export const useStakingContractInfo = () => { minimumStakingDuration, } = activeStakingContractInfo; - const isRewardsAvailable = availableRewards > 0; + const isRewardsAvailable = true; // availableRewards > 0; const hasEnoughServiceSlots = serviceIds.length < maxNumServices; const hasEnoughRewardsAndSlots = isRewardsAvailable && hasEnoughServiceSlots; From 59474d11b421922147eb9871764aef96bf7004a9 Mon Sep 17 00:00:00 2001 From: Ardian Date: Tue, 20 Aug 2024 12:33:02 +0200 Subject: [PATCH 82/99] fix: trader hash --- templates/trader.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/trader.yaml b/templates/trader.yaml index 934b2afbb..ac7f44159 100644 --- a/templates/trader.yaml +++ b/templates/trader.yaml @@ -1,6 +1,6 @@ name: "Trader Agent" description: "A single-agent service (sovereign agent) placing bets on Omen" -hash: bafybeidgjgjj5ul6xkubicbemppufgsbx5sr5rwhtrwttk2oivp5bkdnce +hash: bafybeiembjbkmym3ppclc2qnjuwzayibqp4vsv3lfq56fqelqfu6ytgv5i image: https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75 service_version: v0.18.1 home_chain_id: 100 From 4ce058e879f5861a2b20e6f27117c0e587ef85ea Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 20 Aug 2024 16:57:15 +0200 Subject: [PATCH 83/99] chore: isort --- operate/ledger/profiles.py | 2 +- operate/services/protocol.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/operate/ledger/profiles.py b/operate/ledger/profiles.py index c70e9bf27..bf7fa8433 100644 --- a/operate/ledger/profiles.py +++ b/operate/ledger/profiles.py @@ -38,7 +38,7 @@ STAKING = { ChainType.GNOSIS: { "pearl_alpha": "0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A", - "pearl_beta": "0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d" + "pearl_beta": "0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d", } } diff --git a/operate/services/protocol.py b/operate/services/protocol.py index a7b3135fc..120355c94 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -40,7 +40,8 @@ from autonomy.chain.config import ChainConfigs, ChainType, ContractConfigs from autonomy.chain.constants import ( GNOSIS_SAFE_PROXY_FACTORY_CONTRACT, - GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_CONTRACT, MULTISEND_CONTRACT, + GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_CONTRACT, + MULTISEND_CONTRACT, ) from autonomy.chain.service import ( get_agent_instances, @@ -67,9 +68,10 @@ from operate.types import ContractAddresses from operate.utils.gnosis import ( MultiSendOperation, + NULL_ADDRESS, SafeOperation, hash_payload_to_hex, - skill_input_hex_to_payload, NULL_ADDRESS, + skill_input_hex_to_payload, ) from operate.wallet.master import MasterWallet From 8a8e675f2a0b0dd54ebc3dcdb35bebdbf69ec106 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 20 Aug 2024 16:59:27 +0200 Subject: [PATCH 84/99] fix: update user params --- operate/cli.py | 9 +++++++++ operate/services/manage.py | 37 +++++++++++++++++++++++++++---------- operate/services/service.py | 8 ++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index 1eac6a3b6..f4632b70c 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -504,6 +504,14 @@ async def _create_services(request: Request) -> JSONResponse: if operate.password is None: return USER_NOT_LOGGED_IN_ERROR template = await request.json() + + print("!!!!!!!!!!!!!!!!") + from icecream import ic + + ic(template) + print(template) + import sys + manager = operate.service_manager() if len(manager.json) > 0: old_hash = manager.json[0]["hash"] @@ -528,6 +536,7 @@ async def _create_services(request: Request) -> JSONResponse: ) if template.get("deploy", False): + def _fn() -> None: manager.deploy_service_onchain_from_safe(hash=service.hash) # manager.stake_service_on_chain_from_safe(hash=service.hash) # Done inside deploy_service_onchain diff --git a/operate/services/manage.py b/operate/services/manage.py index 730ec5c8d..6acf0b462 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -48,10 +48,7 @@ OnChainUserParams, Service, ) -from operate.types import ( - ServiceTemplate, - LedgerConfig -) +from operate.types import LedgerConfig, ServiceTemplate from operate.utils.gnosis import NULL_ADDRESS from operate.wallet.master import MasterWalletManager @@ -159,7 +156,12 @@ def load_or_create( """ path = self.path / hash if path.exists(): - return Service.load(path=path) + service = Service.load(path=path) + + if service_template is not None: + service.update_user_params_from_template(service_template=service_template) + + return service if service_template is None: raise ValueError( @@ -878,8 +880,8 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data user_params = chain_data.user_params - target_staking_program_id = user_params.staking_program_id - target_staking_contract = STAKING[ledger_config.chain][target_staking_program_id] + target_staking_program = user_params.staking_program_id + target_staking_contract = STAKING[ledger_config.chain][target_staking_program] sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) # TODO fixme @@ -925,13 +927,27 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: service_id=chain_config.chain_data.token, staking_contract=target_staking_contract, ) + self.logger.info("Checking conditions to stake.") + + staking_rewards_available = sftxb.staking_rewards_available(target_staking_contract) + staking_slots_available = sftxb.staking_slots_available(target_staking_contract) + on_chain_state = self._get_on_chain_state(chain_config=chain_config) + current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + + self.logger.info(f"use_staking={chain_config.chain_data.user_params.use_staking}") + self.logger.info(f"{staking_state=}") + self.logger.info(f"{staking_rewards_available=}") + self.logger.info(f"{staking_slots_available=}") + self.logger.info(f"{on_chain_state=}") + self.logger.info(f"{current_staking_program=}") + self.logger.info(f"{target_staking_program=}") if ( chain_config.chain_data.user_params.use_staking and staking_state == StakingState.UNSTAKED - and sftxb.staking_rewards_available(target_staking_contract) - and sftxb.staking_slots_available(target_staking_contract) - and self._get_on_chain_state(chain_config=chain_config) == OnChainState.DEPLOYED + and staking_rewards_available + and staking_slots_available + and on_chain_state == OnChainState.DEPLOYED ): self.logger.info(f"Approving staking: {chain_config.chain_data.token}") sftxb.new_tx().add( @@ -955,6 +971,7 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: service.store() current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + self.logger.info(f"{target_staking_program=}") self.logger.info(f"{current_staking_program=}") def unstake_service_on_chain(self, hash: str) -> None: diff --git a/operate/services/service.py b/operate/services/service.py index 6a476866b..ea6c563ca 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -777,6 +777,14 @@ def new( service.store() return service + def update_user_params_from_template(self, service_template: ServiceTemplate): + """Update user params from template.""" + for chain, config in service_template["configurations"].items(): + for chain, config in service_template["configurations"].items(): + self.chain_configs[chain].chain_data.user_params = OnChainUserParams.from_json(config) + + self.store() + def delete(self) -> None: """Delete a service.""" parent_directory = self.path.parent From 138c553da527df48e57c8a4b0374fc472332940a Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 20 Aug 2024 17:08:12 +0200 Subject: [PATCH 85/99] chore: whitespace --- operate/cli.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index f4632b70c..7d5285d13 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -504,14 +504,6 @@ async def _create_services(request: Request) -> JSONResponse: if operate.password is None: return USER_NOT_LOGGED_IN_ERROR template = await request.json() - - print("!!!!!!!!!!!!!!!!") - from icecream import ic - - ic(template) - print(template) - import sys - manager = operate.service_manager() if len(manager.json) > 0: old_hash = manager.json[0]["hash"] From 0f9f5dc0eb4e8a6e2a5a1f107a3a141aff25d9c5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 20 Aug 2024 17:17:53 +0100 Subject: [PATCH 86/99] bump: rc114 --- electron/install.js | 2 +- package.json | 5 ++--- pyproject.toml | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/electron/install.js b/electron/install.js index 7988e07fa..35eed6e98 100644 --- a/electron/install.js +++ b/electron/install.js @@ -14,7 +14,7 @@ const { paths } = require('./constants'); * - use "" (nothing as a suffix) for latest release candidate, for example "0.1.0rc26" * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ -const OlasMiddlewareVersion = '0.1.0rc112'; +const OlasMiddlewareVersion = '0.1.0rc114'; const path = require('path'); const { app } = require('electron'); diff --git a/package.json b/package.json index 857c15b20..24c7fc52b 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,6 @@ "test:frontend": "cd frontend && yarn test", "download-binaries": "sh download_binaries.sh", "build:pearl": "sh build_pearl.sh" - }, - "version": "0.1.0-rc112" -} + "version": "0.1.0-rc114" +} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index b77f08413..a9462612f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc112" +version = "0.1.0-rc114" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From 2e368cbf003675e003e53df9aea2083f8796a4ae Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 20 Aug 2024 18:15:25 +0100 Subject: [PATCH 87/99] fix: conflict resolution, electron-store 8.2 pin --- electron/store.js | 5 +- frontend/context/BalanceProvider.tsx | 23 +++ package.json | 2 +- yarn.lock | 232 ++++++++++++++++++--------- 4 files changed, 180 insertions(+), 82 deletions(-) diff --git a/electron/store.js b/electron/store.js index b8c5c9093..eafd9428a 100644 --- a/electron/store.js +++ b/electron/store.js @@ -1,3 +1,4 @@ +const Store = require('electron-store'); // set schema to validate store data const schema = { isInitialFunded: { type: 'boolean', default: false }, // TODO: reconsider this default, can be problematic if user has already funded prior to implementation @@ -16,8 +17,6 @@ const schema = { * @returns {Promise} - A promise that resolves once the store is set up. */ const setupStoreIpc = async (ipcMain, mainWindow) => { - const Store = (await import("electron-store")).default; - const store = new Store({ schema }); store.onDidAnyChange((data) => { @@ -30,7 +29,7 @@ const setupStoreIpc = async (ipcMain, mainWindow) => { ipcMain.handle('store-get', (_, key) => store.get(key)); ipcMain.handle('store-set', (_, key, value) => store.set(key, value)); ipcMain.handle('store-delete', (_, key) => store.delete(key)); - ipcMain.handle('store-clear', (_) => store.clear()); + ipcMain.handle('store-clear', (_) => store.clear()); }; module.exports = { setupStoreIpc }; diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index cc417462a..dfcc70e6c 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -17,6 +17,10 @@ import { useInterval } from 'usehooks-ts'; import { Wallet } from '@/client'; import { CHAINS } from '@/constants/chains'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { + LOW_AGENT_SAFE_BALANCE, + LOW_MASTER_SAFE_BALANCE, +} from '@/constants/thresholds'; import { TOKENS } from '@/constants/tokens'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { Token } from '@/enums/Token'; @@ -44,6 +48,7 @@ export const BalanceContext = createContext<{ safeBalance?: ValueOf; totalEthBalance?: number; totalOlasBalance?: number; + isLowBalance: boolean; wallets?: Wallet[]; walletBalances: WalletAddressNumberRecord; updateBalances: () => Promise; @@ -59,6 +64,7 @@ export const BalanceContext = createContext<{ safeBalance: undefined, totalEthBalance: undefined, totalOlasBalance: undefined, + isLowBalance: false, wallets: undefined, walletBalances: {}, updateBalances: async () => {}, @@ -197,6 +203,22 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { () => masterSafeAddress && walletBalances[masterSafeAddress], [masterSafeAddress, walletBalances], ); + const agentSafeBalance = useMemo( + () => + services?.[0]?.chain_data?.multisig && + walletBalances[services[0].chain_data.multisig], + [services, walletBalances], + ); + const isLowBalance = useMemo(() => { + if (!safeBalance || !agentSafeBalance) return false; + if ( + safeBalance.ETH < LOW_MASTER_SAFE_BALANCE && + // Need to check agentSafe balance as well, because it's auto-funded from safeBalance + agentSafeBalance.ETH < LOW_AGENT_SAFE_BALANCE + ) + return true; + return false; + }, [safeBalance, agentSafeBalance]); useInterval( () => { @@ -217,6 +239,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { safeBalance, totalEthBalance, totalOlasBalance, + isLowBalance, wallets, walletBalances, updateBalances, diff --git a/package.json b/package.json index b90fa2de7..c5afe288e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "cross-env": "^7.0.3", "dotenv": "^16.4.5", "electron-log": "^5.1.4", - "electron-store": "^9.0.0", + "electron-store": "8.2.0", "electron-updater": "^6.1.8", "ethers": "5.7.2", "ethers-multicall": "^0.2.3", diff --git a/yarn.lock b/yarn.lock index 0d084c194..146feb635 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1347,7 +1347,7 @@ ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.12.0: +ajv@^8.0.0: version "8.16.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.16.0.tgz#22e2a92b94f005f7e0f9c9d39652ef0b8f6f0cb4" integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== @@ -1357,6 +1357,16 @@ ajv@^8.0.0, ajv@^8.12.0: require-from-string "^2.0.2" uri-js "^4.4.1" +ajv@^8.6.3: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + ansi-colors@^4.1.1, ansi-colors@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" @@ -1538,13 +1548,10 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -atomically@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/atomically/-/atomically-2.0.3.tgz#27e47bbe39994d324918491ba7c0edb7783e56cb" - integrity sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw== - dependencies: - stubborn-fs "^1.2.5" - when-exit "^2.1.1" +atomically@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/atomically/-/atomically-1.7.0.tgz#c07a0458432ea6dbc9a3506fffa424b48bccaafe" + integrity sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w== axios@^1.7.2: version "1.7.2" @@ -2024,20 +2031,21 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -conf@^12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/conf/-/conf-12.0.0.tgz#de7a5f091114a28bc52aa5eecc920f4710d60d7f" - integrity sha512-fIWyWUXrJ45cHCIQX+Ck1hrZDIf/9DR0P0Zewn3uNht28hbt5OfGUq8rRWsxi96pZWPyBEd0eY9ama01JTaknA== +conf@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/conf/-/conf-10.2.0.tgz#838e757be963f1a2386dfe048a98f8f69f7b55d6" + integrity sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg== dependencies: - ajv "^8.12.0" + ajv "^8.6.3" ajv-formats "^2.1.1" - atomically "^2.0.2" - debounce-fn "^5.1.2" - dot-prop "^8.0.2" - env-paths "^3.0.0" - json-schema-typed "^8.0.1" - semver "^7.5.4" - uint8array-extras "^0.3.0" + atomically "^1.7.0" + debounce-fn "^4.0.0" + dot-prop "^6.0.1" + env-paths "^2.2.1" + json-schema-typed "^7.0.3" + onetime "^5.1.2" + pkg-up "^3.1.0" + semver "^7.3.5" config-file-ts@^0.2.4: version "0.2.6" @@ -2139,12 +2147,12 @@ dayjs@^1.11.11: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.11.tgz#dfe0e9d54c5f8b68ccf8ca5f72ac603e7e5ed59e" integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg== -debounce-fn@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/debounce-fn/-/debounce-fn-5.1.2.tgz#c77bc447ef36828ecdd066df7de23f475e0a6281" - integrity sha512-Sr4SdOZ4vw6eQDvPYNxHogvrxmCIld/VenC5JbNrFwMiwd7lY/Z18ZFfo+EWNG4DD9nFlAujWAo/wGuOPHmy5A== +debounce-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/debounce-fn/-/debounce-fn-4.0.0.tgz#ed76d206d8a50e60de0dd66d494d82835ffe61c7" + integrity sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ== dependencies: - mimic-fn "^4.0.0" + mimic-fn "^3.0.0" debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5: version "4.3.5" @@ -2256,12 +2264,12 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dot-prop@^8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-8.0.2.tgz#afda6866610684dd155a96538f8efcdf78a27f18" - integrity sha512-xaBe6ZT4DHPkg0k4Ytbvn5xoxgpG0jOS1dYxSOwAHPuNLjP3/OzN0gH55SrLqpx8cBfSaVt91lXYkApjb+nYdQ== +dot-prop@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" + integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== dependencies: - type-fest "^3.8.0" + is-obj "^2.0.0" dotenv-cli@^7.4.2: version "7.4.2" @@ -2345,13 +2353,13 @@ electron-publish@24.13.1: lazy-val "^1.0.5" mime "^2.5.2" -electron-store@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/electron-store/-/electron-store-9.0.0.tgz#7ce8209c5ae31877ee5fbced6c6cb538c746ca8c" - integrity sha512-7LZ2dR3N3bF93G2c4x+1NZ/8fpsKv6bKrMxeOQWLqdRbxvopxVqy9QXQy9axSV2O3P1kVGTj1q2wq5/W4isiOg== +electron-store@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/electron-store/-/electron-store-8.2.0.tgz#114e6e453e8bb746ab4ccb542424d8c881ad2ca1" + integrity sha512-ukLL5Bevdil6oieAOXz3CMy+OgaItMiVBg701MNlG6W5RaC0AHN7rvlqTCmeb6O7jP0Qa1KKYTE0xV0xbhF4Hw== dependencies: - conf "^12.0.0" - type-fest "^4.18.1" + conf "^10.2.0" + type-fest "^2.17.0" electron-updater@^6.1.8: version "6.2.1" @@ -2432,16 +2440,11 @@ enquirer@^2.3.0: ansi-colors "^4.1.1" strip-ansi "^6.0.1" -env-paths@^2.2.0: +env-paths@^2.2.0, env-paths@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== -env-paths@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-3.0.0.tgz#2f1e89c2f6dbd3408e1b1711dd82d62e317f58da" - integrity sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A== - err-code@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" @@ -2742,6 +2745,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== + fastq@^1.6.0: version "1.17.1" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" @@ -2789,6 +2797,13 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -3371,6 +3386,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -3462,10 +3482,10 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema-typed@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/json-schema-typed/-/json-schema-typed-8.0.1.tgz#826ee39e3b6cef536f85412ff048d3ff6f19dfa0" - integrity sha512-XQmWYj2Sm4kn4WeTYvmpKEbyPsL7nBsb647c7pMe6l02/yx2+Jfc4dT6UZkEXnIUb5LhD55r2HPsJ1milQ4rDg== +json-schema-typed@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/json-schema-typed/-/json-schema-typed-7.0.3.tgz#23ff481b8b4eebcd2ca123b4fa0409e66469a2d9" + integrity sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A== json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" @@ -3583,6 +3603,14 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -3728,10 +3756,15 @@ mime@^2.5.2: resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== -mimic-fn@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" - integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" + integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== mimic-response@^1.0.0: version "1.0.1" @@ -3949,6 +3982,13 @@ one-time@^1.0.0: dependencies: fn.name "1.x.x" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -3978,6 +4018,13 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -3992,6 +4039,13 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -4011,6 +4065,11 @@ p-try@^1.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + package-json-from-dist@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" @@ -4089,6 +4148,13 @@ picomatch@^2.0.4, picomatch@^2.2.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pkg-up@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + plist@^3.0.4, plist@^3.0.5: version "3.1.0" resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.0.tgz#797a516a93e62f5bde55e0b9cc9c967f860893c9" @@ -4800,11 +4866,16 @@ semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.2, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: +semver@^7.3.2, semver@^7.3.8, semver@^7.5.3: version "7.6.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== +semver@^7.3.5: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + serialize-error@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" @@ -4971,7 +5042,16 @@ string-convert@^0.2.0: resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4996,7 +5076,14 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -5022,11 +5109,6 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -stubborn-fs@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/stubborn-fs/-/stubborn-fs-1.2.5.tgz#e5e244223166921ddf66ed5e062b6b3bf285bfd2" - integrity sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g== - styled-components@^6.1.8: version "6.1.11" resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.11.tgz#01948e5195bf1d39e57e0a85b41958c80e40cfb8" @@ -5245,26 +5327,16 @@ type-fest@^0.7.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== -type-fest@^3.8.0: - version "3.13.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.13.1.tgz#bb744c1f0678bea7543a2d1ec24e83e68e8c8706" - integrity sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g== - -type-fest@^4.18.1: - version "4.21.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.21.0.tgz#2eec399d9bda4ac686286314d07c6675fef3fdd8" - integrity sha512-ADn2w7hVPcK6w1I0uWnM//y1rLXZhzB9mr0a3OirzclKF1Wp6VzevUmzz/NRAWunOT6E8HrnpGY7xOfc6K57fA== +type-fest@^2.17.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== typescript@^5.3.3: version "5.5.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa" integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ== -uint8array-extras@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/uint8array-extras/-/uint8array-extras-0.3.0.tgz#4b5714e4bf15bb36ae7fd6faeef11aae34a0af59" - integrity sha512-erJsJwQ0tKdwuqI0359U8ijkFmfiTcq25JvvzRVc1VP+2son1NJRXhxcAKJmAW3ajM8JSGAfsAXye8g4s+znxA== - undici-types@~5.26.4: version "5.26.5" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" @@ -5330,11 +5402,6 @@ verror@^1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -when-exit@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/when-exit/-/when-exit-2.1.3.tgz#5831cdbed8ad4984645da98c4a00d4ee3a3757e7" - integrity sha512-uVieSTccFIr/SFQdFWN/fFaQYmV37OKtuaGphMAzi4DmmUlrvRBJW5WSLkHyjNQY/ePJMz3LoiX9R3yy1Su6Hw== - which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -5378,7 +5445,16 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== From 5b237b9bf923fa8586fc922d2bc2622467b8e226 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 20 Aug 2024 18:18:44 +0100 Subject: [PATCH 88/99] fix: balance provider type merge conflict resolution --- frontend/context/BalanceProvider.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index dfcc70e6c..2bee8e074 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -205,8 +205,11 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { ); const agentSafeBalance = useMemo( () => - services?.[0]?.chain_data?.multisig && - walletBalances[services[0].chain_data.multisig], + services?.[0]?.chain_configs[CHAINS.GNOSIS.chainId].chain_data + ?.multisig && + walletBalances[ + services[0].chain_configs[CHAINS.GNOSIS.chainId].chain_data.multisig! + ], [services, walletBalances], ); const isLowBalance = useMemo(() => { From bb4104acb4a66d5a1c77e5138c33be995be4c7de Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 20 Aug 2024 18:30:09 +0100 Subject: [PATCH 89/99] fix: custom alert import --- frontend/components/MainPage/header/AgentButton.tsx | 2 -- frontend/components/MainPage/sections/NeedsFundsSection.tsx | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton.tsx index 24ac0e71f..6fcdbdea0 100644 --- a/frontend/components/MainPage/header/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton.tsx @@ -4,7 +4,6 @@ import { useCallback, useMemo } from 'react'; import { Chain, DeploymentStatus } from '@/client'; import { COLOR } from '@/constants/colors'; -import { LOW_BALANCE } from '@/constants/thresholds'; import { StakingProgram } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; @@ -238,7 +237,6 @@ const AgentNotRunningButton = () => { return hasEnoughOlas && hasEnoughEth; }, [ serviceStatus, - safeBalance, service, storeState?.isInitialFunded, isEligibleForStaking, diff --git a/frontend/components/MainPage/sections/NeedsFundsSection.tsx b/frontend/components/MainPage/sections/NeedsFundsSection.tsx index 3b22c46f4..08ae82696 100644 --- a/frontend/components/MainPage/sections/NeedsFundsSection.tsx +++ b/frontend/components/MainPage/sections/NeedsFundsSection.tsx @@ -3,6 +3,7 @@ import { formatUnits } from 'ethers/lib/utils'; import { ReactNode, useEffect, useMemo } from 'react'; import styled from 'styled-components'; +import { CustomAlert } from '@/components/Alert'; import { CHAINS } from '@/constants/chains'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { useBalance } from '@/hooks/useBalance'; @@ -11,8 +12,6 @@ import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { useStore } from '@/hooks/useStore'; import { getMinimumStakedAmountRequired } from '@/utils/service'; -import { CustomAlert } from '../../Alert'; -import { AlertTitle } from '../../Alert/AlertTitle'; import { CardSection } from '../../styled/CardSection'; const { Text } = Typography; From 717714b5e0b3ac4e0bd3348caffa9f267a841242 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 21 Aug 2024 10:08:19 +0100 Subject: [PATCH 90/99] fix: gitleaks ignore 2 keys --- .gitleaksignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitleaksignore b/.gitleaksignore index 446eb5a4b..33c8c27cf 100644 --- a/.gitleaksignore +++ b/.gitleaksignore @@ -27,4 +27,6 @@ d8149e9b5b7bd6a7ed7bc1039900702f1d4f287b:operate/services/manage.py:generic-api- 99c0f139b037da2587708212fcf6d0e20786d0ba:operate/services/manage.py:generic-api-key:406 99c0f139b037da2587708212fcf6d0e20786d0ba:operate/services/manage.py:generic-api-key:454 99c0f139b037da2587708212fcf6d0e20786d0ba:operate/services/manage.py:generic-api-key:455 -91ec07457f69e9a29f63693ac8ef887e4b5f49f0:operate/services/manage.py:generic-api-key:454 \ No newline at end of file +91ec07457f69e9a29f63693ac8ef887e4b5f49f0:operate/services/manage.py:generic-api-key:454 +410bea2bd02ff54da69387fe8f3b58793e09f7b0:operate/services/manage.py:generic-api-key:421 +410bea2bd02ff54da69387fe8f3b58793e09f7b0:operate/services/manage.py:generic-api-key:422 \ No newline at end of file From c54ab4b556bc6930db8114a36c5138d8bb6c9ff7 Mon Sep 17 00:00:00 2001 From: Ardian Date: Wed, 21 Aug 2024 12:55:43 +0200 Subject: [PATCH 91/99] fix: update trader hash --- frontend/constants/serviceTemplates.ts | 2 +- templates/trader.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index dcb2fd1aa..19948f76a 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -4,7 +4,7 @@ import { StakingProgram } from '@/enums/StakingProgram'; export const SERVICE_TEMPLATES: ServiceTemplate[] = [ { name: 'Trader Agent', - hash: 'bafybeidgjgjj5ul6xkubicbemppufgsbx5sr5rwhtrwttk2oivp5bkdnce', + hash: 'bafybeicrstlxew36hlxl7pzi73nmd44aibnhwxzkchzlec6t6yhvs7gvhy', // hash: 'bafybeibbloa4w33vj4bvdkso7pzk6tr3duvxjpecbx4mur4ix6ehnwb5uu', // temporary description: 'Trader agent for omen prediction markets', image: diff --git a/templates/trader.yaml b/templates/trader.yaml index ac7f44159..ed0b8679d 100644 --- a/templates/trader.yaml +++ b/templates/trader.yaml @@ -1,6 +1,6 @@ name: "Trader Agent" description: "A single-agent service (sovereign agent) placing bets on Omen" -hash: bafybeiembjbkmym3ppclc2qnjuwzayibqp4vsv3lfq56fqelqfu6ytgv5i +hash: bafybeicrstlxew36hlxl7pzi73nmd44aibnhwxzkchzlec6t6yhvs7gvhy image: https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75 service_version: v0.18.1 home_chain_id: 100 From ea7eef01f442eb676cb04ff37ca05422d85741f5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 21 Aug 2024 13:25:33 +0100 Subject: [PATCH 92/99] fix: missed minimum required olas string --- .../ManageStakingPage/StakingContractSection/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index b8fdf664c..d10180fd9 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -136,7 +136,7 @@ export const StakingContractSection = ({ } if (!hasEnoughOlasToMigrate) { - return 'Insufficient OLAS balance to migrate, need ${}'; + return `Insufficient OLAS balance to migrate, ${minimumOlasRequiredToMigrate} OLAS minimum required.`; } if (!isAppVersionCompatible) { From bb6eef73882e5796dc5b046d672086b11c25d93d Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:27:05 +0100 Subject: [PATCH 93/99] refactor: wordiness --- .../ManageStakingPage/StakingContractSection/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index d10180fd9..9302ef843 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -136,7 +136,7 @@ export const StakingContractSection = ({ } if (!hasEnoughOlasToMigrate) { - return `Insufficient OLAS balance to migrate, ${minimumOlasRequiredToMigrate} OLAS minimum required.`; + return `Insufficient OLAS balance to migrate, ${minimumOlasRequiredToMigrate} OLAS required.`; } if (!isAppVersionCompatible) { From fba4aacac0ffee7729363f009242090e35614e57 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:27:45 +0100 Subject: [PATCH 94/99] Update index.tsx --- .../ManageStakingPage/StakingContractSection/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index 9302ef843..363f7ce55 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -136,7 +136,7 @@ export const StakingContractSection = ({ } if (!hasEnoughOlasToMigrate) { - return `Insufficient OLAS balance to migrate, ${minimumOlasRequiredToMigrate} OLAS required.`; + return `Insufficient OLAS to migrate, ${minimumOlasRequiredToMigrate} OLAS required in total.`; } if (!isAppVersionCompatible) { From 15816fe07e1ed95b7474f9a634213d4d00e00632 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 21 Aug 2024 17:05:58 +0100 Subject: [PATCH 95/99] fix: provider order --- frontend/pages/_app.tsx | 52 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 42657f818..9227cb596 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -28,19 +28,19 @@ export default function App({ Component, pageProps }: AppProps) { }, []); return ( - - - - - - - - - - - - - + + + + + + + + + + + + + {isMounted ? ( @@ -50,18 +50,18 @@ export default function App({ Component, pageProps }: AppProps) { ) : null} - - - - - - - - - - - - - + + + + + + + + + + + + + ); } From ac5c6ca0f00fd9a003302869de7fc2c88d3c0b94 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 21 Aug 2024 17:23:06 +0100 Subject: [PATCH 96/99] chore: bump 116 for testing staging with rewards fix --- electron/install.js | 2 +- package.json | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/electron/install.js b/electron/install.js index 2c3de2faa..efebf9180 100644 --- a/electron/install.js +++ b/electron/install.js @@ -14,7 +14,7 @@ const { paths } = require('./constants'); * - use "" (nothing as a suffix) for latest release candidate, for example "0.1.0rc26" * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ -const OlasMiddlewareVersion = '0.1.0rc115'; +const OlasMiddlewareVersion = '0.1.0rc116'; const path = require('path'); const { app } = require('electron'); diff --git a/package.json b/package.json index c5afe288e..5eaea98ea 100644 --- a/package.json +++ b/package.json @@ -58,5 +58,5 @@ "download-binaries": "sh download_binaries.sh", "build:pearl": "sh build_pearl.sh" }, - "version": "0.1.0-rc115" + "version": "0.1.0-rc116" } \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 9a58deb5d..db96e9913 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc115" +version = "0.1.0-rc116" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From 973b5d2884a805b8ec0e2c42488c831bd7557e37 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:51:47 +0100 Subject: [PATCH 97/99] Bump --- electron/install.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electron/install.js b/electron/install.js index efebf9180..a43856a9b 100644 --- a/electron/install.js +++ b/electron/install.js @@ -14,7 +14,7 @@ const { paths } = require('./constants'); * - use "" (nothing as a suffix) for latest release candidate, for example "0.1.0rc26" * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ -const OlasMiddlewareVersion = '0.1.0rc116'; +const OlasMiddlewareVersion = '0.1.0rc117'; const path = require('path'); const { app } = require('electron'); From 21a035e0d052cbfc53ef65c26dcd1908d00372a4 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:52:06 +0100 Subject: [PATCH 98/99] Bump --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5eaea98ea..b50e8fe5f 100644 --- a/package.json +++ b/package.json @@ -58,5 +58,5 @@ "download-binaries": "sh download_binaries.sh", "build:pearl": "sh build_pearl.sh" }, - "version": "0.1.0-rc116" -} \ No newline at end of file + "version": "0.1.0-rc117" +} From 219814e19127be0b3b945fab8cdec7eed53ab4c4 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:52:22 +0100 Subject: [PATCH 99/99] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index db96e9913..3c4bce6cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc116" +version = "0.1.0-rc117" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md"