diff --git a/README.md b/README.md index ed0edf5e2..9ebefc76c 100644 --- a/README.md +++ b/README.md @@ -90,8 +90,6 @@ export ALL_PARTICIPANTS='["YOUR_AGENT_ADDRESS"]' export SAFE_CONTRACT_ADDRESS="YOUR_SAFE_ADDRESS" export OMEN_CREATORS='["0x89c5cc945dd550BcFfb72Fe42BfF002429F46Fec"]' -export MECH_TOOL="prediction-online" - export BET_AMOUNT_PER_THRESHOLD_000=0 export BET_AMOUNT_PER_THRESHOLD_010=0 export BET_AMOUNT_PER_THRESHOLD_020=0 @@ -117,12 +115,6 @@ These are the description of the variables used by the Trader service: - `SAFE_CONTRACT_ADDRESS`: address of the agents multisig wallet created [in the previous section](#prepare-the-keys-and-the-safe). - `OMEN_CREATORS`: addresses of the market creator(s) that the service will track for placing bets on Omen. The address `0x89c5cc945dd550BcFfb72Fe42BfF002429F46Fec` corresponds to the Market creator agent for the Hackathon. -- `MECH_TOOL`: the tool that the service will use to get the prediction when performing requests to the AI Mech. - You may find all the available Mech scripts [here](https://github.com/valory-xyz/mech/tree/v0.5.0/tools) - for Mech's version `v0.5.0`. - Each script contains one or more tools. - For example, you may find all the `prediction_request` tools - [here](https://github.com/valory-xyz/mech/blob/v0.5.0/tools/prediction_request.py#L37-L40). - `BET_AMOUNT_PER_THRESHOLD_X`: amount (wei) to bet when the prediction returned by the AI Mech surpasses a threshold of `X`% confidence for a given prediction market. In the values provided above the amounts vary between 0.03 xDAI (60% confidence) and 0.1 xDAI (100% confidence). - `BET_THRESHOLD`: threshold (wei) for placing a bet. A bet will only be placed if `potential_net_profit - BET_THRESHOLD >= 0`. [See below](#some-notes-on-the-service). - `PROMPT_TEMPLATE`: prompt to be used with the prediction AI Mech. Please keep it as a single line including the placeholders `@{question}`, `@{yes}` and `@{no}`. diff --git a/packages/packages.json b/packages/packages.json index 8d2577be6..4e30c4652 100644 --- a/packages/packages.json +++ b/packages/packages.json @@ -1,17 +1,18 @@ { "dev": { - "skill/valory/market_manager_abci/0.1.0": "bafybeicqrgxbf2pocfh7332qzhcshwsarpwjkj3zroveklsrovozcppsvq", - "skill/valory/decision_maker_abci/0.1.0": "bafybeihwjudh7pngsgflbrfe2kcvzkaq2edl5j3l3wb463eeagcwpaluay", - "skill/valory/trader_abci/0.1.0": "bafybeihgug7lpiuqoxjabfsqc337skofs67iljxs5ounvbqlu5e7ny3e4u", + "skill/valory/market_manager_abci/0.1.0": "bafybeig223xrxbtfx5adwhc7m6rpdbevsqm5osfq66oijucs2gzn4hehsm", + "skill/valory/decision_maker_abci/0.1.0": "bafybeieqyd5jek55q57lg77hey3oapppoosaphhyxxlulx52gg2ahkqdba", + "skill/valory/trader_abci/0.1.0": "bafybeighllbhqgeryjaew2heequ4iyaghevr3vnvvpx2pl3foqopk4k4zi", "contract/valory/market_maker/0.1.0": "bafybeiftimqgvrbval2lxp7au6y72amioo4gtcdth2dflrbwa47i6opyb4", - "agent/valory/trader/0.1.0": "bafybeicmdnhfkx5d4fn2cyliscl4szazkaswgupzpzl33ql4cymtvygq5m", - "service/valory/trader/0.1.0": "bafybeig75imqyexby56t5udvkxikiapvo767hlygf6iczf4zgzc4vo7upy", + "agent/valory/trader/0.1.0": "bafybeibabgxao6ljhmwiztsquug3v6i6jo4s3izlk4zs4so4jfnvfqbxnm", + "service/valory/trader/0.1.0": "bafybeiaq5frvxzehiqyifdvvs35tspv7a32wp7ve7u7o6nflrkvbza6yhu", "contract/valory/erc20/0.1.0": "bafybeifjwr6rwklgg2uk2zkfysn55qqy7dfi4jx7sek6lzdup37fynhpxe", - "skill/valory/tx_settlement_multiplexer_abci/0.1.0": "bafybeiab2iz65fsus7h3kk5j3unw6guzvtpfe6ytrcmayay5x2phqsxdlu", - "contract/valory/mech/0.1.0": "bafybeie753wdqks6k4x5fqlpo7tgll2avutjcaodpwlptqvzefsi5xbvai", + "skill/valory/tx_settlement_multiplexer_abci/0.1.0": "bafybeidel3rxm55y2qqewhmwroybs5j7t6ma6awmxbo7xjv3jvhmb6dv7m", + "contract/valory/mech/0.1.0": "bafybeiehjnwd63xp6ttfsskhxsphnvpjpwrfqzfltjvqn6mjqkemoo2qge", "contract/valory/realitio/0.1.0": "bafybeicdgm2a7evjw6szcpo3uaam5mzd6axtevtzwvejr6uaeymbg437da", "contract/valory/realitio_proxy/0.1.0": "bafybeibvndq6756qck7forgeavhdbn6ykgqs2ufyg7n5g6qdfpveatxuwy", - "contract/valory/conditional_tokens/0.1.0": "bafybeicxwjdbmjajgr5rsmadtkxxwmcm42r2htef3tvng73uzib4hmb6qa" + "contract/valory/conditional_tokens/0.1.0": "bafybeicxwjdbmjajgr5rsmadtkxxwmcm42r2htef3tvng73uzib4hmb6qa", + "contract/valory/agent_registry/0.1.0": "bafybeid3knh7d7uzvtkbdg7xxdjajjb3lhusxju46iydkt5p4wklc4gz5e" }, "third_party": { "protocol/open_aea/signing/1.0.0": "bafybeifuxs7gdg2okbn7uofymenjlmnih2wxwkym44lsgwmklgwuckxm2m", diff --git a/packages/valory/agents/trader/aea-config.yaml b/packages/valory/agents/trader/aea-config.yaml index 10d50769d..4f3f43392 100644 --- a/packages/valory/agents/trader/aea-config.yaml +++ b/packages/valory/agents/trader/aea-config.yaml @@ -21,7 +21,7 @@ contracts: - valory/market_maker:0.1.0:bafybeiftimqgvrbval2lxp7au6y72amioo4gtcdth2dflrbwa47i6opyb4 - valory/erc20:0.1.0:bafybeifjwr6rwklgg2uk2zkfysn55qqy7dfi4jx7sek6lzdup37fynhpxe - valory/multisend:0.1.0:bafybeie7m7pjbnw7cccpbvmbgkut24dtlt4cgvug3tbac7gej37xvwbv3a -- valory/mech:0.1.0:bafybeie753wdqks6k4x5fqlpo7tgll2avutjcaodpwlptqvzefsi5xbvai +- valory/mech:0.1.0:bafybeiehjnwd63xp6ttfsskhxsphnvpjpwrfqzfltjvqn6mjqkemoo2qge - valory/conditional_tokens:0.1.0:bafybeicxwjdbmjajgr5rsmadtkxxwmcm42r2htef3tvng73uzib4hmb6qa - valory/realitio:0.1.0:bafybeicdgm2a7evjw6szcpo3uaam5mzd6axtevtzwvejr6uaeymbg437da - valory/realitio_proxy:0.1.0:bafybeibvndq6756qck7forgeavhdbn6ykgqs2ufyg7n5g6qdfpveatxuwy @@ -41,10 +41,10 @@ skills: - valory/reset_pause_abci:0.1.0:bafybeifoihgilpfr76hc5skzspm6qehkwivx7ld2cy3veipcsi4gr2c7na - valory/termination_abci:0.1.0:bafybeigcsls72uosoui2y5ppmnvsljjhnxakkeh3fdohklcg66aqq4g7xu - valory/transaction_settlement_abci:0.1.0:bafybeiglsnh2hvfau5gab7requh34k4sbqwbjvrhhqjpes4hakcwq46cpi -- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeiab2iz65fsus7h3kk5j3unw6guzvtpfe6ytrcmayay5x2phqsxdlu -- valory/market_manager_abci:0.1.0:bafybeicqrgxbf2pocfh7332qzhcshwsarpwjkj3zroveklsrovozcppsvq -- valory/decision_maker_abci:0.1.0:bafybeihwjudh7pngsgflbrfe2kcvzkaq2edl5j3l3wb463eeagcwpaluay -- valory/trader_abci:0.1.0:bafybeihgug7lpiuqoxjabfsqc337skofs67iljxs5ounvbqlu5e7ny3e4u +- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeidel3rxm55y2qqewhmwroybs5j7t6ma6awmxbo7xjv3jvhmb6dv7m +- valory/market_manager_abci:0.1.0:bafybeig223xrxbtfx5adwhc7m6rpdbevsqm5osfq66oijucs2gzn4hehsm +- valory/decision_maker_abci:0.1.0:bafybeieqyd5jek55q57lg77hey3oapppoosaphhyxxlulx52gg2ahkqdba +- valory/trader_abci:0.1.0:bafybeighllbhqgeryjaew2heequ4iyaghevr3vnvvpx2pl3foqopk4k4zi default_ledger: ethereum required_ledgers: - ethereum @@ -147,6 +147,7 @@ models: multisend_address: ${str:0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761} drand_public_key: ${str:868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31} service_registry_address: ${str:null} + agent_registry_address: ${str:null} share_tm_config_on_startup: ${bool:false} sleep_time: ${int:10} tendermint_p2p_url: ${str:localhost:26656} @@ -161,7 +162,6 @@ models: average_block_time: ${int:5} abt_error_mult: ${int:5} mech_agent_address: ${str:0xff82123dfb52ab75c417195c5fdb87630145ae81} - mech_tool: ${str:prediction-online} bet_amount_per_threshold: 0.0: ${int:0} 0.1: ${int:0} @@ -187,6 +187,11 @@ models: redeeming_batch_size: ${int:5} slippage: ${float:0.01} redeem_margin_days: ${int:15} + policy_epsilon: ${float:0.1} + irrelevant_tools: ${list:["openai-text-davinci-002", "openai-text-davinci-003", + "openai-gpt-3.5-turbo", "openai-gpt-4", "stabilityai-stable-diffusion-v1-5", + "stabilityai-stable-diffusion-xl-beta-v2-2-2", "stabilityai-stable-diffusion-512-v2-1", + "stabilityai-stable-diffusion-768-v2-1"]} --- public_id: valory/p2p_libp2p_client:0.1.0 type: connection diff --git a/packages/valory/contracts/agent_registry/__init__.py b/packages/valory/contracts/agent_registry/__init__.py new file mode 100644 index 000000000..cf1e8467e --- /dev/null +++ b/packages/valory/contracts/agent_registry/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 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 agent registry contract.""" diff --git a/packages/valory/contracts/agent_registry/build/AgentRegistry.json b/packages/valory/contracts/agent_registry/build/AgentRegistry.json new file mode 100644 index 000000000..79a56dba2 --- /dev/null +++ b/packages/valory/contracts/agent_registry/build/AgentRegistry.json @@ -0,0 +1,1046 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "AgentRegistry", + "sourceName": "contracts/AgentRegistry.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "string", + "name": "_symbol", + "type": "string" + }, + { + "internalType": "string", + "name": "_baseURI", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "AgentInstanceRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "AgentInstancesSlotsFilled", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "AgentNotFound", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "AgentNotInService", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "componentId", + "type": "uint256" + } + ], + "name": "ComponentNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "HashExists", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "IncorrectAgentBondingValue", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "IncorrectRegistrationDepositValue", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "ManagerOnly", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "provided", + "type": "address" + }, + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "OnlyOwnServiceMultisig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "OperatorHasNoInstances", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "OperatorOnly", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "provided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "Overflow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerOnly", + "type": "error" + }, + { + "inputs": [], + "name": "Paused", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuard", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "ServiceMustBeInactive", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TransferFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "multisig", + "type": "address" + } + ], + "name": "UnauthorizedMultisig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "WrongAgentId", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "numValues1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "numValues2", + "type": "uint256" + } + ], + "name": "WrongArrayLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "WrongOperator", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "state", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "WrongServiceState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "currentThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minThreshold", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxThreshold", + "type": "uint256" + } + ], + "name": "WrongThreshold", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValue", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "baseURI", + "type": "string" + } + ], + "name": "BaseURIChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "agentHash", + "type": "bytes32" + } + ], + "name": "CreateAgent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "ManagerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "agentHash", + "type": "bytes32" + } + ], + "name": "UpdateAgentHash", + "type": "event" + }, + { + "inputs": [], + "name": "CID_PREFIX", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "baseURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newManager", + "type": "address" + } + ], + "name": "changeManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "changeOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "agentOwner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "agentHash", + "type": "bytes32" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "unitId", + "type": "uint256" + } + ], + "name": "exists", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "getHashes", + "outputs": [ + { + "internalType": "uint256", + "name": "numHashes", + "type": "uint256" + }, + { + "internalType": "bytes32[]", + "name": "agentHashes", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "manager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapAgentIdHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "bURI", + "type": "string" + } + ], + "name": "setBaseURI", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "tokenByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "unitId", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "unitId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "agentHash", + "type": "bytes32" + } + ], + "name": "updateHash", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "", + "deployedBytecode": "", + "linkReferences": {}, + "deployedLinkReferences": {} +} \ No newline at end of file diff --git a/packages/valory/contracts/agent_registry/contract.py b/packages/valory/contracts/agent_registry/contract.py new file mode 100644 index 000000000..9acf29aad --- /dev/null +++ b/packages/valory/contracts/agent_registry/contract.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 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 Agent Registry contract.""" + +from aea.common import JSONLike +from aea.configurations.base import PublicId +from aea.contracts.base import Contract +from aea.crypto.base import LedgerApi + + +class AgentRegistryContract(Contract): + """The Agent Registry contract.""" + + contract_id = PublicId.from_str("valory/agent_registry:0.1.0") + + @classmethod + def get_hash( + cls, + ledger_api: LedgerApi, + contract_address: str, + agent_id: int, + ) -> JSONLike: + """Retrieve an operator given its agent instance.""" + + contract_instance = cls.get_instance(ledger_api, contract_address) + res = contract_instance.functions.getHashes(agent_id).call() + # ensure that the returned object has the expected format + if len(res) != 2: + msg = f"The `getHashes` method for {contract_address=} returned data in an unexpected format: {res}" + return dict(error=msg) + + # get the agent hashes + hashes = res.pop(-1) + # ensure that there are hashes returned for the agent + if len(hashes) == 0: + msg = f"The `getHashes` method for {contract_address=} returned no hashes for {agent_id=}: {res}" + return dict(error=msg) + + # get the most recent agent hash + hash_ = hashes.pop(-1) + # ensure that the hash is in bytes + if not isinstance(hash_, bytes): + msg = f"The `getHashes` method for {contract_address=} returned non-bytes {hash_=} for {agent_id=}: {res}" + return dict(error=msg) + + # return the hash in hex + return dict(hash=hash_.hex()) diff --git a/packages/valory/contracts/agent_registry/contract.yaml b/packages/valory/contracts/agent_registry/contract.yaml new file mode 100644 index 000000000..9e40c0f3e --- /dev/null +++ b/packages/valory/contracts/agent_registry/contract.yaml @@ -0,0 +1,23 @@ +name: agent_registry +author: valory +version: 0.1.0 +type: contract +description: Agent Registry contract +license: Apache-2.0 +aea_version: '>=1.0.0, <2.0.0' +fingerprint: + __init__.py: bafybeid3wfzglolebuo6jrrsopswzu4lk77bm76mvw3euizlsjtnt3wmgu + build/AgentRegistry.json: bafybeicoe5elvvsv2neiirsdn4uddrilizmyib3x4mvpklr7olhj2kh4ue + contract.py: bafybeihrv6blme3v6diwci6zxxn72qbg5sanzmfq5tobhs4375ebcuyday +fingerprint_ignore_patterns: [] +contracts: [] +class_name: AgentRegistryContract +contract_interface_paths: + ethereum: build/AgentRegistry.json +dependencies: + open-aea-ledger-ethereum: + version: ==1.38.0 + open-aea-test-autonomy: + version: ==0.12.0 + open-aea-web3: + version: ==6.0.1 diff --git a/packages/valory/contracts/mech/contract.py b/packages/valory/contracts/mech/contract.py index cc2cab58d..85966e0d5 100644 --- a/packages/valory/contracts/mech/contract.py +++ b/packages/valory/contracts/mech/contract.py @@ -184,3 +184,14 @@ def get_response( return {"error": error} return dict(data=deliver_args["data"]) + + @classmethod + def get_mech_id( + cls, + ledger_api: EthereumApi, + contract_address: str, + ) -> JSONLike: + """Get the price of a request.""" + contract_instance = cls.get_instance(ledger_api, contract_address) + mech_id = ledger_api.contract_method_call(contract_instance, "tokenId") + return dict(id=mech_id) diff --git a/packages/valory/contracts/mech/contract.yaml b/packages/valory/contracts/mech/contract.yaml index 63b1c80ed..780474955 100644 --- a/packages/valory/contracts/mech/contract.yaml +++ b/packages/valory/contracts/mech/contract.yaml @@ -9,7 +9,7 @@ fingerprint: README.md: bafybeibl4uw7rs6mwh7zuvdnqmj2o2xyr7nx5qk3w7torwx3jg6farn6ca __init__.py: bafybeicx5pxh3cxnml2biuuoebvafvu5tvy6mgkzyjzuubuoeebb5yzjsm build/mech.json: bafybeihsfz7rdnf6cpa3c4eagvs4pw6jhr6pcsikstakejrlkuwvwzhw7m - contract.py: bafybeigypn3frcjr7mcmdoe5ubgoy57owm4bfcgtrcytiu76u7khthlvei + contract.py: bafybeifbfa6p3jcwn6j7s5aiiqxb3ne4vbmvoggr5zpptmd727gpsjqjpe fingerprint_ignore_patterns: [] contracts: [] class_name: Mech diff --git a/packages/valory/services/trader/service.yaml b/packages/valory/services/trader/service.yaml index c01982bcc..cc2765eb0 100644 --- a/packages/valory/services/trader/service.yaml +++ b/packages/valory/services/trader/service.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 fingerprint: README.md: bafybeigtuothskwyvrhfosps2bu6suauycolj67dpuxqvnicdrdu7yhtvq fingerprint_ignore_patterns: [] -agent: valory/trader:0.1.0:bafybeicmdnhfkx5d4fn2cyliscl4szazkaswgupzpzl33ql4cymtvygq5m +agent: valory/trader:0.1.0:bafybeibabgxao6ljhmwiztsquug3v6i6jo4s3izlk4zs4so4jfnvfqbxnm number_of_agents: 4 deployment: {} --- @@ -57,6 +57,7 @@ type: skill round_timeout_seconds: ${ROUND_TIMEOUT:float:350.0} service_id: ${SERVICE_ID:str:trader} service_registry_address: ${SERVICE_REGISTRY_ADDRESS:str:0x9338b5153AE39BB89f50468E608eD9d764B755fD} + agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} share_tm_config_on_startup: ${USE_ACN:bool:false} sleep_time: ${SLEEP_TIME:int:1} tendermint_check_sleep_delay: ${TM_CHECK_SLEEP_DELAY:int:3} @@ -77,7 +78,6 @@ type: skill average_block_time: ${ABT:int:5} abt_error_mult: ${ABT_ERROR_MULT:int:5} mech_agent_address: ${MECH_AGENT_ADDRESS:str:0xff82123dfb52ab75c417195c5fdb87630145ae81} - mech_tool: ${MECH_TOOL:str:prediction-online} bet_amount_per_threshold: &id004 0.0: ${BET_AMOUNT_PER_THRESHOLD_000:int:0} 0.1: ${BET_AMOUNT_PER_THRESHOLD_010:int:0} @@ -104,6 +104,11 @@ type: skill redeeming_batch_size: ${REDEEMING_BATCH_SIZE:int:1} slippage: ${SLIPPAGE:float:0.01} redeem_margin_days: ${REDEEM_MARGIN_DAYS:int:15} + policy_epsilon: ${POLICY_EPSILON:float:0.1} + irrelevant_tools: ${IRRELEVANT_TOOLS:list:["openai-text-davinci-002", "openai-text-davinci-003", + "openai-gpt-3.5-turbo", "openai-gpt-4", "stabilityai-stable-diffusion-v1-5", + "stabilityai-stable-diffusion-xl-beta-v2-2-2", "stabilityai-stable-diffusion-512-v2-1", + "stabilityai-stable-diffusion-768-v2-1"]} benchmark_tool: &id005 args: log_dir: ${LOG_DIR:str:/benchmarks} @@ -133,6 +138,7 @@ type: skill round_timeout_seconds: ${ROUND_TIMEOUT:float:350.0} service_id: ${SERVICE_ID:str:trader} service_registry_address: ${SERVICE_REGISTRY_ADDRESS:str:0x9338b5153AE39BB89f50468E608eD9d764B755fD} + agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} share_tm_config_on_startup: ${USE_ACN:bool:false} sleep_time: ${SLEEP_TIME:int:1} tendermint_check_sleep_delay: ${TM_CHECK_SLEEP_DELAY:int:3} @@ -152,7 +158,6 @@ type: skill average_block_time: ${ABT:int:5} abt_error_mult: ${ABT_ERROR_MULT:int:5} mech_agent_address: ${MECH_AGENT_ADDRESS:str:0xff82123dfb52ab75c417195c5fdb87630145ae81} - mech_tool: ${MECH_TOOL:str:prediction-online} bet_amount_per_threshold: *id004 bet_threshold: ${BET_THRESHOLD:int:100000000000000000} blacklisting_duration: ${BLACKLISTING_DURATION:int:3600} @@ -168,6 +173,11 @@ type: skill redeeming_batch_size: ${REDEEMING_BATCH_SIZE:int:1} slippage: ${SLIPPAGE:float:0.01} redeem_margin_days: ${REDEEM_MARGIN_DAYS:int:15} + policy_epsilon: ${POLICY_EPSILON:float:0.1} + irrelevant_tools: ${IRRELEVANT_TOOLS:list:["openai-text-davinci-002", "openai-text-davinci-003", + "openai-gpt-3.5-turbo", "openai-gpt-4", "stabilityai-stable-diffusion-v1-5", + "stabilityai-stable-diffusion-xl-beta-v2-2-2", "stabilityai-stable-diffusion-512-v2-1", + "stabilityai-stable-diffusion-768-v2-1"]} benchmark_tool: *id005 2: models: @@ -195,6 +205,7 @@ type: skill round_timeout_seconds: ${ROUND_TIMEOUT:float:350.0} service_id: ${SERVICE_ID:str:trader} service_registry_address: ${SERVICE_REGISTRY_ADDRESS:str:0x9338b5153AE39BB89f50468E608eD9d764B755fD} + agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} share_tm_config_on_startup: ${USE_ACN:bool:false} sleep_time: ${SLEEP_TIME:int:1} tendermint_check_sleep_delay: ${TM_CHECK_SLEEP_DELAY:int:3} @@ -214,7 +225,6 @@ type: skill average_block_time: ${ABT:int:5} abt_error_mult: ${ABT_ERROR_MULT:int:5} mech_agent_address: ${MECH_AGENT_ADDRESS:str:0xff82123dfb52ab75c417195c5fdb87630145ae81} - mech_tool: ${MECH_TOOL:str:prediction-online} bet_amount_per_threshold: *id004 bet_threshold: ${BET_THRESHOLD:int:100000000000000000} blacklisting_duration: ${BLACKLISTING_DURATION:int:3600} @@ -230,6 +240,11 @@ type: skill redeeming_batch_size: ${REDEEMING_BATCH_SIZE:int:1} slippage: ${SLIPPAGE:float:0.01} redeem_margin_days: ${REDEEM_MARGIN_DAYS:int:15} + policy_epsilon: ${POLICY_EPSILON:float:0.1} + irrelevant_tools: ${IRRELEVANT_TOOLS:list:["openai-text-davinci-002", "openai-text-davinci-003", + "openai-gpt-3.5-turbo", "openai-gpt-4", "stabilityai-stable-diffusion-v1-5", + "stabilityai-stable-diffusion-xl-beta-v2-2-2", "stabilityai-stable-diffusion-512-v2-1", + "stabilityai-stable-diffusion-768-v2-1"]} benchmark_tool: *id005 3: models: @@ -257,6 +272,7 @@ type: skill round_timeout_seconds: ${ROUND_TIMEOUT:float:350.0} service_id: ${SERVICE_ID:str:trader} service_registry_address: ${SERVICE_REGISTRY_ADDRESS:str:0x9338b5153AE39BB89f50468E608eD9d764B755fD} + agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} share_tm_config_on_startup: ${USE_ACN:bool:false} sleep_time: ${SLEEP_TIME:int:1} tendermint_check_sleep_delay: ${TM_CHECK_SLEEP_DELAY:int:3} @@ -276,7 +292,6 @@ type: skill average_block_time: ${ABT:int:5} abt_error_mult: ${ABT_ERROR_MULT:int:5} mech_agent_address: ${MECH_AGENT_ADDRESS:str:0xff82123dfb52ab75c417195c5fdb87630145ae81} - mech_tool: ${MECH_TOOL:str:prediction-online} bet_amount_per_threshold: *id004 bet_threshold: ${BET_THRESHOLD:int:100000000000000000} blacklisting_duration: ${BLACKLISTING_DURATION:int:3600} @@ -292,6 +307,11 @@ type: skill redeeming_batch_size: ${REDEEMING_BATCH_SIZE:int:1} slippage: ${SLIPPAGE:float:0.01} redeem_margin_days: ${REDEEM_MARGIN_DAYS:int:15} + policy_epsilon: ${POLICY_EPSILON:float:0.1} + irrelevant_tools: ${IRRELEVANT_TOOLS:list:["openai-text-davinci-002", "openai-text-davinci-003", + "openai-gpt-3.5-turbo", "openai-gpt-4", "stabilityai-stable-diffusion-v1-5", + "stabilityai-stable-diffusion-xl-beta-v2-2-2", "stabilityai-stable-diffusion-512-v2-1", + "stabilityai-stable-diffusion-768-v2-1"]} benchmark_tool: *id005 --- public_id: valory/ledger:0.19.0 diff --git a/packages/valory/skills/decision_maker_abci/behaviours/base.py b/packages/valory/skills/decision_maker_abci/behaviours/base.py index 889a40483..01a159fe9 100644 --- a/packages/valory/skills/decision_maker_abci/behaviours/base.py +++ b/packages/valory/skills/decision_maker_abci/behaviours/base.py @@ -42,6 +42,7 @@ DecisionMakerParams, MultisendBatch, ) +from packages.valory.skills.decision_maker_abci.policy import EGreedyPolicy from packages.valory.skills.decision_maker_abci.states.base import SynchronizedData from packages.valory.skills.transaction_settlement_abci.payload_tools import ( hash_payload_to_hex, @@ -56,6 +57,7 @@ # which is what we want in most cases # more info here: https://safe-docs.dev.gnosisdev.com/safe/docs/contracts_tx_execution/ SAFE_GAS = 0 +CID_PREFIX = "f01701220" def remove_fraction_wei(amount: int, fraction: float) -> int: @@ -75,6 +77,7 @@ def __init__(self, **kwargs: Any) -> None: self.multisend_batches: List[MultisendBatch] = [] self.multisend_data = b"" self._safe_tx_hash = "" + self._policy: Optional[EGreedyPolicy] = None @property def params(self) -> DecisionMakerParams: @@ -129,6 +132,20 @@ def tx_hex(self) -> Optional[str]: SafeOperation.DELEGATE_CALL.value, ) + @property + def policy(self) -> EGreedyPolicy: + """Get the policy.""" + if self._policy is None: + raise ValueError( + "Attempting to retrieve the policy before it has been established." + ) + return self._policy + + @property + def is_first_period(self) -> bool: + """Return whether it is the first period of the service.""" + return self.synchronized_data.period_count == 0 + @staticmethod def wei_to_native(wei: int) -> float: """Convert WEI to native token.""" diff --git a/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py b/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py index 342537407..fd3506eef 100644 --- a/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py +++ b/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py @@ -26,6 +26,7 @@ from packages.valory.protocols.contract_api import ContractApiMessage from packages.valory.skills.abstract_round_abci.base import get_name from packages.valory.skills.decision_maker_abci.behaviours.base import ( + CID_PREFIX, DecisionMakerBaseBehaviour, WaitableConditionType, remove_fraction_wei, @@ -41,7 +42,6 @@ from packages.valory.skills.market_manager_abci.bets import BINARY_N_SLOTS -IPFS_HASH_PREFIX = "f01701220" ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" @@ -103,7 +103,7 @@ def mech_response_api(self) -> MechResponseSpecs: def set_mech_response_specs(self) -> None: """Set the mech's response specs.""" - full_ipfs_hash = IPFS_HASH_PREFIX + self.response_hex + full_ipfs_hash = CID_PREFIX + self.response_hex ipfs_link = self.params.ipfs_address + full_ipfs_hash + f"/{self.request_id}" # The url must be dynamically generated as it depends on the ipfs hash self.mech_response_api.__dict__["_frozen"] = False @@ -112,7 +112,7 @@ def set_mech_response_specs(self) -> None: @property def mech_response(self) -> MechInteractionResponse: - """Get the mech response api specs.""" + """Get the mech's response.""" if self._mech_response is None: error = "The mech's response has not been set!" return MechInteractionResponse(error=error) diff --git a/packages/valory/skills/decision_maker_abci/behaviours/decision_request.py b/packages/valory/skills/decision_maker_abci/behaviours/decision_request.py index 456702efe..13d006308 100644 --- a/packages/valory/skills/decision_maker_abci/behaviours/decision_request.py +++ b/packages/valory/skills/decision_maker_abci/behaviours/decision_request.py @@ -120,7 +120,8 @@ def setup(self) -> None: question=sampled_bet.title, yes=sampled_bet.yes, no=sampled_bet.no ) prompt = self.params.prompt_template.substitute(prompt_params) - self._metadata = MechMetadata(prompt=prompt, tool=self.params.mech_tool) + tool = self.synchronized_data.mech_tool + self._metadata = MechMetadata(prompt, tool) msg = f"Prepared metadata {self.metadata!r} for the request." self.context.logger.info(msg) diff --git a/packages/valory/skills/decision_maker_abci/behaviours/reedem.py b/packages/valory/skills/decision_maker_abci/behaviours/reedem.py index c88b0a32c..4f257b8db 100644 --- a/packages/valory/skills/decision_maker_abci/behaviours/reedem.py +++ b/packages/valory/skills/decision_maker_abci/behaviours/reedem.py @@ -19,6 +19,7 @@ """This module contains the redeeming state of the decision-making abci app.""" +import json from abc import ABC from collections import defaultdict from sys import maxsize @@ -39,7 +40,7 @@ WaitableConditionType, ) from packages.valory.skills.decision_maker_abci.models import MultisendBatch -from packages.valory.skills.decision_maker_abci.payloads import MultisigTxPayload +from packages.valory.skills.decision_maker_abci.payloads import RedeemPayload from packages.valory.skills.decision_maker_abci.redeem_info import ( Condition, FPMM, @@ -66,6 +67,7 @@ class RedeemInfoBehaviour(DecisionMakerBaseBehaviour, QueryingBehaviour, ABC): def __init__(self, **kwargs: Any) -> None: """Initialize a `RedeemInfo` object.""" super().__init__(**kwargs) + self.utilized_tools: Dict[str, int] = {} self.trades: Set[Trade] = set() # blocks in which the markets were created mapped to the corresponding condition ids @@ -86,6 +88,11 @@ def synced_timestamp(self) -> int: """Return the synchronized timestamp across the agents.""" return int(self.round_sequence.last_round_transition_timestamp.timestamp()) + def setup(self) -> None: + """Setup the behaviour""" + self._policy = self.synchronized_data.policy + self.utilized_tools = self.synchronized_data.utilized_tools + def _set_block_number(self, trade: Trade) -> Generator: """Set the block number of the given trade's market.""" timestamp = trade.fpmm.creationTimestamp @@ -105,6 +112,30 @@ def _set_block_number(self, trade: Trade) -> Generator: f"Chose block number {self.from_block_mapping[condition_id]!r} as closest to timestamp {timestamp!r}" ) + def _update_policy(self, update: Trade) -> None: + """Update the policy.""" + claimable_xdai = self.wei_to_native(update.claimable_amount) + # the mapping might not contain a tool for a bet placement because it might have happened on a previous run + tool_index = self.utilized_tools.get(update.transactionHash, None) + if tool_index is not None: + # we try to avoid an ever-increasing dictionary of utilized tools by removing a tool when not needed anymore + del self.utilized_tools[update.transactionHash] + self.policy.add_reward(tool_index, claimable_xdai) + + def _stats_report(self) -> None: + """Report policy statistics.""" + stats_report = "Policy statistics so far (only for resolved markets):\n" + available_tools = self.synchronized_data.available_mech_tools + for i, tool in enumerate(available_tools): + stats_report += ( + f"{tool} tool:\n" + f"\tTimes used: {self.policy.counts[i]}\n" + f"\tReward rate: {self.policy.reward_rates[i]}\n" + ) + best_tool = available_tools[self.policy.best_tool] + stats_report += f"Best tool so far is {best_tool!r}." + self.context.logger.info(stats_report) + def update_redeem_info(self, chunk: list) -> Generator: """Update the redeeming information using the given chunk.""" trades_updates: Iterator[Trade] = ( @@ -115,6 +146,8 @@ def update_redeem_info(self, chunk: list) -> Generator: ) for update in trades_updates: + self._update_policy(update) + # do not use the information if position is not winning if not update.is_winning: continue @@ -132,6 +165,9 @@ def update_redeem_info(self, chunk: list) -> Generator: if update == unique_obj: self.claimable_amounts[condition_id] += update.claimable_amount + if self.policy.has_updated: + self._stats_report() + class RedeemBehaviour(RedeemInfoBehaviour): """Redeem the winnings.""" @@ -554,11 +590,14 @@ def async_act(self) -> Generator: yield from self._clean_redeem_info() agent = self.context.agent_address redeem_tx_hex = yield from self._prepare_safe_tx() - tx_submitter = ( - self.matching_round.auto_round_id() - if redeem_tx_hex is not None - else None + tx_submitter = policy = utilized_tools = None + if redeem_tx_hex is not None: + tx_submitter = self.matching_round.auto_round_id() + policy = self.policy.serialize() + utilized_tools = json.dumps(self.utilized_tools) + + payload = RedeemPayload( + agent, tx_submitter, redeem_tx_hex, policy, utilized_tools ) - payload = MultisigTxPayload(agent, tx_submitter, redeem_tx_hex) yield from self.finish_behaviour(payload) diff --git a/packages/valory/skills/decision_maker_abci/behaviours/round_behaviour.py b/packages/valory/skills/decision_maker_abci/behaviours/round_behaviour.py index 49be37e88..af7643e54 100644 --- a/packages/valory/skills/decision_maker_abci/behaviours/round_behaviour.py +++ b/packages/valory/skills/decision_maker_abci/behaviours/round_behaviour.py @@ -44,6 +44,9 @@ from packages.valory.skills.decision_maker_abci.behaviours.sampling import ( SamplingBehaviour, ) +from packages.valory.skills.decision_maker_abci.behaviours.tool_selection import ( + ToolSelectionBehaviour, +) from packages.valory.skills.decision_maker_abci.rounds import DecisionMakerAbciApp @@ -60,4 +63,5 @@ class AgentDecisionMakerRoundBehaviour(AbstractRoundBehaviour): BetPlacementBehaviour, # type: ignore RedeemBehaviour, # type: ignore HandleFailedTxBehaviour, # type: ignore + ToolSelectionBehaviour, # type: ignore } diff --git a/packages/valory/skills/decision_maker_abci/behaviours/tool_selection.py b/packages/valory/skills/decision_maker_abci/behaviours/tool_selection.py new file mode 100644 index 000000000..6d9e94de3 --- /dev/null +++ b/packages/valory/skills/decision_maker_abci/behaviours/tool_selection.py @@ -0,0 +1,224 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 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 behaviour of the skill which is responsible for selecting a mech tool.""" + +import json +from typing import Any, Dict, Generator, List, Optional + +from packages.valory.contracts.agent_registry.contract import AgentRegistryContract +from packages.valory.protocols.contract_api import ContractApiMessage +from packages.valory.skills.abstract_round_abci.base import get_name +from packages.valory.skills.decision_maker_abci.behaviours.base import ( + CID_PREFIX, + DecisionMakerBaseBehaviour, + WaitableConditionType, +) +from packages.valory.skills.decision_maker_abci.models import AgentToolsSpecs +from packages.valory.skills.decision_maker_abci.payloads import ToolSelectionPayload +from packages.valory.skills.decision_maker_abci.policy import EGreedyPolicy +from packages.valory.skills.decision_maker_abci.states.tool_selection import ( + ToolSelectionRound, +) + + +class ToolSelectionBehaviour(DecisionMakerBaseBehaviour): + """A behaviour in which the agents select a mech tool.""" + + matching_round = ToolSelectionRound + + def __init__(self, **kwargs: Any) -> None: + """Initialize Behaviour.""" + super().__init__(**kwargs) + self._mech_id: int = 0 + self._mech_hash: str = "" + self._mech_tools: Optional[List[str]] = None + + @property + def mech_id(self) -> int: + """Get the mech's id.""" + return self._mech_id + + @mech_id.setter + def mech_id(self, mech_id: int) -> None: + """Set the mech's id.""" + self._mech_id = mech_id + + @property + def mech_hash(self) -> str: + """Get the hash of the mech agent.""" + return self._mech_hash + + @mech_hash.setter + def mech_hash(self, mech_hash: str) -> None: + """Set the hash of the mech agent.""" + self._mech_hash = mech_hash + + @property + def mech_tools(self) -> List[str]: + """Get the mech agent's tools.""" + if self._mech_tools is None: + raise ValueError("The mech's tools have not been set.") + return self._mech_tools + + @mech_tools.setter + def mech_tools(self, mech_tools: List[str]) -> None: + """Set the mech agent's tools.""" + self._mech_tools = mech_tools + + @property + def utilized_tools(self) -> Dict[str, int]: + """Get the utilized tools.""" + if self.is_first_period: + return {} + return self.synchronized_data.utilized_tools + + @property + def mech_tools_api(self) -> AgentToolsSpecs: + """Get the mech agent api specs.""" + return self.context.agent_tools + + def set_mech_agent_specs(self) -> None: + """Set the mech's agent specs.""" + full_ipfs_hash = CID_PREFIX + self.mech_hash + ipfs_link = self.params.ipfs_address + full_ipfs_hash + # The url needs to be dynamically generated as it depends on the ipfs hash + self.mech_tools_api.__dict__["_frozen"] = False + self.mech_tools_api.url = ipfs_link + self.mech_tools_api.__dict__["_frozen"] = True + + def _get_mech_id(self) -> WaitableConditionType: + """Get the mech's id.""" + result = yield from self._mech_contract_interact( + contract_callable="get_mech_id", + data_key="id", + placeholder=get_name(ToolSelectionBehaviour.mech_id), + ) + + return result + + def _get_mech_hash(self) -> WaitableConditionType: + """Get the mech's hash.""" + result = yield from self.contract_interact( + performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, # type: ignore + contract_address=self.params.agent_registry_address, + contract_public_id=AgentRegistryContract.contract_id, + contract_callable="get_hash", + data_key="hash", + placeholder=get_name(ToolSelectionBehaviour.mech_hash), + agent_id=self.mech_id, + ) + return result + + def _get_mech_tools(self) -> WaitableConditionType: + """Get the mech agent's tools from IPFS.""" + self.set_mech_agent_specs() + specs = self.mech_tools_api.get_spec() + res_raw = yield from self.get_http_response(**specs) + res = self.mech_tools_api.process_response(res_raw) + + if self.mech_tools_api.is_retries_exceeded(): + error = "Retries were exceeded while trying to get the mech agent's data." + self.context.logger.error(error) + return True + + if res is None: + msg = f"Could not get the mech agent's tools from {self.mech_tools_api.api_id}" + self.context.logger.error(msg) + self.mech_tools_api.increment_retries() + return False + + self.context.logger.info(f"Retrieved the mech agent's tools: {res}.") + # keep only the relevant mech tools, sorted + # we sort the tools to avoid using dictionaries in the policy implementation, + # so that we can easily assess which index corresponds to which tool + res = sorted(set(res) - self.params.irrelevant_tools) + self.context.logger.info(f"Relevant tools to the prediction task: {res}.") + + if len(res) == 0: + self.context.logger.error("The relevant mech agent's tools are empty!") + return False + self.mech_tools = res + self.mech_tools_api.reset_retries() + return True + + def _get_tools( + self, + ) -> Generator[None, None, None]: + """Get the Mech's tools.""" + for step in ( + self._get_mech_id, + self._get_mech_hash, + self._get_mech_tools, + ): + yield from self.wait_for_condition_with_sleep(step) + + def _adjust_policy_tools(self) -> None: + """Add or remove tools from the policy to match the remote tools.""" + local = self.synchronized_data.available_mech_tools + + # remove tools if they are not available anymore + # process the indices in reverse order to avoid index shifting when removing the unavailable tools later + reversed_idx = range(len(local) - 1, -1, -1) + removed_idx = [idx for idx in reversed_idx if local[idx] not in self.mech_tools] + self.policy.remove_tools(removed_idx) + + # add tools if there are new ones available + # process the indices in reverse order to avoid index shifting when adding the new tools later + reversed_idx = range(len(self.mech_tools) - 1, -1, -1) + new_idx = [idx for idx in reversed_idx if self.mech_tools[idx] not in local] + self.policy.add_new_tools(new_idx) + + def _set_policy(self) -> None: + """Set the E Greedy Policy.""" + if self.is_first_period: + n_relevant = len(self.mech_tools) + self._policy = EGreedyPolicy.initial_state(self.params.epsilon, n_relevant) + else: + self._policy = self.synchronized_data.policy + self._adjust_policy_tools() + + def _select_tool(self) -> Generator[None, None, Optional[int]]: + """Select a Mech tool based on an e-greedy policy and return its index.""" + yield from self._get_tools() + self._set_policy() + selected = self.policy.select_tool() + self.context.logger.info(f"Selected the mech tool {selected!r}.") + return selected + + def async_act(self) -> Generator: + """Do the action.""" + + with self.context.benchmark_tool.measure(self.behaviour_id).local(): + mech_tools = policy = utilized_tools = None + selected_tool = yield from self._select_tool() + if selected_tool is not None: + mech_tools = json.dumps(self.mech_tools) + policy = self.policy.serialize() + utilized_tools = json.dumps(self.utilized_tools, sort_keys=True) + + payload = ToolSelectionPayload( + self.context.agent_address, + mech_tools, + policy, + utilized_tools, + selected_tool, + ) + + yield from self.finish_behaviour(payload) diff --git a/packages/valory/skills/decision_maker_abci/fsm_specification.yaml b/packages/valory/skills/decision_maker_abci/fsm_specification.yaml index 9fb83b998..28ae210b7 100644 --- a/packages/valory/skills/decision_maker_abci/fsm_specification.yaml +++ b/packages/valory/skills/decision_maker_abci/fsm_specification.yaml @@ -38,6 +38,7 @@ states: - RedeemRound - RefillRequiredRound - SamplingRound +- ToolSelectionRound transition_func: (BetPlacementRound, DONE): FinishedDecisionMakerRound (BetPlacementRound, INSUFFICIENT_BALANCE): RefillRequiredRound @@ -68,7 +69,11 @@ transition_func: (RedeemRound, NO_MAJORITY): RedeemRound (RedeemRound, NO_REDEEMING): FinishedWithoutRedeemingRound (RedeemRound, ROUND_TIMEOUT): RedeemRound - (SamplingRound, DONE): DecisionRequestRound + (SamplingRound, DONE): ToolSelectionRound (SamplingRound, NONE): FinishedWithoutDecisionRound (SamplingRound, NO_MAJORITY): SamplingRound (SamplingRound, ROUND_TIMEOUT): SamplingRound + (ToolSelectionRound, DONE): DecisionRequestRound + (ToolSelectionRound, NONE): ToolSelectionRound + (ToolSelectionRound, NO_MAJORITY): ToolSelectionRound + (ToolSelectionRound, ROUND_TIMEOUT): ToolSelectionRound diff --git a/packages/valory/skills/decision_maker_abci/models.py b/packages/valory/skills/decision_maker_abci/models.py index 4b861687c..b440f6678 100644 --- a/packages/valory/skills/decision_maker_abci/models.py +++ b/packages/valory/skills/decision_maker_abci/models.py @@ -92,7 +92,6 @@ class DecisionMakerParams(MarketManagerParams): def __init__(self, *args: Any, **kwargs: Any) -> None: """Initialize the parameters' object.""" self.mech_agent_address: str = self._ensure("mech_agent_address", kwargs, str) - self.mech_tool: str = self._ensure("mech_tool", kwargs, str) # this is a mapping from the confidence of a bet's choice to the amount we are willing to bet self.bet_amount_per_threshold: Dict[float, int] = self._ensure( "bet_amount_per_threshold", kwargs, Dict[float, int] @@ -122,7 +121,12 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.redeeming_batch_size = self._ensure("redeeming_batch_size", kwargs, int) # a slippage in the range of [0, 1] to apply to the `minOutcomeTokensToBuy` when buying shares on a fpmm self._slippage = 0.0 - self.slippage = self._ensure("slippage", kwargs, float) + self.slippage: float = self._ensure("slippage", kwargs, float) + self.epsilon: float = self._ensure("policy_epsilon", kwargs, float) + self.agent_registry_address: str = self._ensure( + "agent_registry_address", kwargs, str + ) + self.irrelevant_tools: set = set(self._ensure("irrelevant_tools", kwargs, list)) super().__init__(*args, **kwargs) @property @@ -161,6 +165,10 @@ class MechResponseSpecs(ApiSpecs): """A model that wraps ApiSpecs for the Mech's response specifications.""" +class AgentToolsSpecs(ApiSpecs): + """A model that wraps ApiSpecs for the Mech agent's tools specifications.""" + + @dataclass class MultisendBatch: """A structure representing a single transaction of a multisend.""" diff --git a/packages/valory/skills/decision_maker_abci/payloads.py b/packages/valory/skills/decision_maker_abci/payloads.py index 1aea905b7..7d03ac0d3 100644 --- a/packages/valory/skills/decision_maker_abci/payloads.py +++ b/packages/valory/skills/decision_maker_abci/payloads.py @@ -50,6 +50,14 @@ class MultisigTxPayload(BaseTxPayload): tx_hash: Optional[str] +@dataclass(frozen=True) +class RedeemPayload(MultisigTxPayload): + """Represents a transaction payload for preparing an on-chain transaction for redeeming.""" + + policy: Optional[str] + utilized_tools: Optional[str] + + @dataclass(frozen=True) class RequestPayload(MultisigTxPayload): """Represents a transaction payload for preparing an on-chain transaction for a mech request.""" @@ -62,3 +70,13 @@ class VotingPayload(BaseTxPayload): """Represents a transaction payload for voting.""" vote: bool + + +@dataclass(frozen=True) +class ToolSelectionPayload(BaseTxPayload): + """Represents a transaction payload for selecting a mech tool.""" + + mech_tools: Optional[str] + policy: Optional[str] + utilized_tools: Optional[str] + index: Optional[int] diff --git a/packages/valory/skills/decision_maker_abci/policy.py b/packages/valory/skills/decision_maker_abci/policy.py new file mode 100644 index 000000000..96b9afa2b --- /dev/null +++ b/packages/valory/skills/decision_maker_abci/policy.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 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 an Epsilon Greedy Policy implementation.""" + +import json +import random +from dataclasses import asdict, dataclass, is_dataclass +from typing import Any, List, Optional + + +class DataclassEncoder(json.JSONEncoder): + """A custom JSON encoder for dataclasses.""" + + def default(self, o: Any) -> Any: + """The default JSON encoder.""" + if is_dataclass(o): + return asdict(o) + return super().default(o) + + +def argmax(li: List) -> int: + """Get the index of the max value within the provided list.""" + return li.index((max(li))) + + +@dataclass +class EGreedyPolicy: + """An e-Greedy policy for the tool selection.""" + + eps: float + counts: List[int] + rewards: List[float] + initial_value = 0 + + @classmethod + def initial_state(cls, eps: float, n_tools: int) -> "EGreedyPolicy": + """Return an instance on its initial state.""" + if n_tools <= 0 or eps > 1 or eps < 0: + error = f"Cannot initialize an e Greedy Policy with {eps=} and {n_tools=}" + raise ValueError(error) + + return EGreedyPolicy( + eps, + [cls.initial_value] * n_tools, + [float(cls.initial_value)] * n_tools, + ) + + @classmethod + def deserialize(cls, policy: str) -> "EGreedyPolicy": + """Deserialize a string to an `EGreedyPolicy` object.""" + return EGreedyPolicy(**json.loads(policy)) + + @property + def n_tools(self) -> int: + """Get the number of the policy's tools.""" + return len(self.counts) + + @property + def random_tool(self) -> int: + """Get the index of a tool randomly.""" + return random.randrange(self.n_tools) # nosec + + @property + def has_updated(self) -> bool: + """Whether the policy has ever been updated since its genesis or not.""" + return sum(self.counts) > 0 + + @property + def reward_rates(self) -> List[float]: + """Get the reward rates.""" + return [ + reward / count if count > 0 else 0 + for reward, count in zip(self.rewards, self.counts) + ] + + @property + def best_tool(self) -> int: + """Get the best tool.""" + return argmax(self.reward_rates) + + def add_new_tools(self, indexes: List[int], avoid_shift: bool = False) -> None: + """Add new tools to the current policy.""" + if avoid_shift: + indexes = sorted(indexes, reverse=True) + + for i in indexes: + self.counts.insert(i, self.initial_value) + self.rewards.insert(i, float(self.initial_value)) + + def remove_tools(self, indexes: List[int], avoid_shift: bool = False) -> None: + """Remove the knowledge for the tools corresponding to the given indexes.""" + if avoid_shift: + indexes = sorted(indexes, reverse=True) + + for i in indexes: + try: + del self.counts[i] + del self.rewards[i] + except IndexError as exc: + error = "Attempted to remove tools using incorrect indexes!" + raise ValueError(error) from exc + + def select_tool(self) -> Optional[int]: + """Select a Mech tool and return its index.""" + if self.n_tools == 0: + return None + + if sum(self.counts) == 0 or random.random() < self.eps: # nosec + return self.random_tool + + return self.best_tool + + def add_reward(self, index: int, reward: float) -> None: + """Add a reward for the tool corresponding to the given index.""" + self.counts[index] += 1 + self.rewards[index] += reward + + def serialize(self) -> str: + """Return the policy serialized.""" + return json.dumps(self, cls=DataclassEncoder, sort_keys=True) diff --git a/packages/valory/skills/decision_maker_abci/redeem_info.py b/packages/valory/skills/decision_maker_abci/redeem_info.py index 6e4a2a940..082c0c9b1 100644 --- a/packages/valory/skills/decision_maker_abci/redeem_info.py +++ b/packages/valory/skills/decision_maker_abci/redeem_info.py @@ -52,7 +52,6 @@ class Question: id: bytes data: str - answers: List def __post_init__(self) -> None: """Post initialization to adjust the values.""" @@ -101,6 +100,7 @@ class Trade: outcomeIndex: int outcomeTokenMarginalPrice: float outcomeTokensTraded: int + transactionHash: str def __post_init__(self) -> None: """Post initialization to adjust the values.""" @@ -124,14 +124,17 @@ def __hash__(self) -> int: """Custom hashing operator.""" return hash(self.fpmm.condition.id) + hash(self.fpmm.question.id) - @property - def claimable_amount(self) -> int: - """Get the claimable amount of the current market.""" - return int(self.outcomeTokenMarginalPrice * self.outcomeTokensTraded) - @property def is_winning(self) -> bool: """Return whether the current position is winning.""" our_answer = self.outcomeIndex correct_answer = self.fpmm.current_answer_index return our_answer == correct_answer + + @property + def claimable_amount(self) -> int: + """Get the claimable amount of the current market.""" + amount = int(self.outcomeTokenMarginalPrice * self.outcomeTokensTraded) + if self.is_winning: + return amount + return -amount diff --git a/packages/valory/skills/decision_maker_abci/rounds.py b/packages/valory/skills/decision_maker_abci/rounds.py index ba22eace7..ad80a1ffe 100644 --- a/packages/valory/skills/decision_maker_abci/rounds.py +++ b/packages/valory/skills/decision_maker_abci/rounds.py @@ -55,6 +55,9 @@ ) from packages.valory.skills.decision_maker_abci.states.redeem import RedeemRound from packages.valory.skills.decision_maker_abci.states.sampling import SamplingRound +from packages.valory.skills.decision_maker_abci.states.tool_selection import ( + ToolSelectionRound, +) from packages.valory.skills.market_manager_abci.rounds import ( Event as MarketManagerEvent, ) @@ -70,49 +73,54 @@ class DecisionMakerAbciApp(AbciApp[Event]): Transition states: 0. SamplingRound - done: 1. - - none: 8. + - none: 9. - no majority: 0. - round timeout: 0. - 1. DecisionRequestRound - - done: 7. - - slots unsupported error: 3. + 1. ToolSelectionRound + - done: 2. + - none: 1. - no majority: 1. - round timeout: 1. - - none: 11. - 2. DecisionReceiveRound - - done: 4. - - mech response error: 3. + 2. DecisionRequestRound + - done: 8. + - slots unsupported error: 4. - no majority: 2. - - tie: 3. - - unprofitable: 3. - round timeout: 2. - 3. BlacklistingRound - - done: 8. - - none: 11. + - none: 12. + 3. DecisionReceiveRound + - done: 5. + - mech response error: 4. - no majority: 3. + - tie: 4. + - unprofitable: 4. - round timeout: 3. - - fetch error: 11. - 4. BetPlacementRound - - done: 7. - - insufficient balance: 10. + 4. BlacklistingRound + - done: 9. + - none: 12. - no majority: 4. - round timeout: 4. - - none: 11. - 5. RedeemRound - - done: 7. - - no redeeming: 9. + - fetch error: 12. + 5. BetPlacementRound + - done: 8. + - insufficient balance: 11. - no majority: 5. - round timeout: 5. - - none: 11. - 6. HandleFailedTxRound - - blacklist: 3. - - no op: 5. + - none: 12. + 6. RedeemRound + - done: 8. + - no redeeming: 10. - no majority: 6. - 7. FinishedDecisionMakerRound - 8. FinishedWithoutDecisionRound - 9. FinishedWithoutRedeemingRound - 10. RefillRequiredRound - 11. ImpossibleRound + - round timeout: 6. + - none: 12. + 7. HandleFailedTxRound + - blacklist: 4. + - no op: 6. + - no majority: 7. + 8. FinishedDecisionMakerRound + 9. FinishedWithoutDecisionRound + 10. FinishedWithoutRedeemingRound + 11. RefillRequiredRound + 12. ImpossibleRound Final states: {FinishedDecisionMakerRound, FinishedWithoutDecisionRound, FinishedWithoutRedeemingRound, ImpossibleRound, RefillRequiredRound} @@ -129,11 +137,17 @@ class DecisionMakerAbciApp(AbciApp[Event]): } transition_function: AbciAppTransitionFunction = { SamplingRound: { - Event.DONE: DecisionRequestRound, + Event.DONE: ToolSelectionRound, Event.NONE: FinishedWithoutDecisionRound, Event.NO_MAJORITY: SamplingRound, Event.ROUND_TIMEOUT: SamplingRound, }, + ToolSelectionRound: { + Event.DONE: DecisionRequestRound, + Event.NONE: ToolSelectionRound, + Event.NO_MAJORITY: ToolSelectionRound, + Event.ROUND_TIMEOUT: ToolSelectionRound, + }, DecisionRequestRound: { Event.DONE: FinishedDecisionMakerRound, Event.SLOTS_UNSUPPORTED_ERROR: BlacklistingRound, @@ -185,6 +199,13 @@ class DecisionMakerAbciApp(AbciApp[Event]): RefillRequiredRound: {}, ImpossibleRound: {}, } + cross_period_persisted_keys = frozenset( + { + get_name(SynchronizedData.available_mech_tools), + get_name(SynchronizedData.policy), + get_name(SynchronizedData.utilized_tools), + } + ) final_states: Set[AppState] = { FinishedDecisionMakerRound, FinishedWithoutDecisionRound, diff --git a/packages/valory/skills/decision_maker_abci/skill.yaml b/packages/valory/skills/decision_maker_abci/skill.yaml index 18d4ddc60..e2a327c9d 100644 --- a/packages/valory/skills/decision_maker_abci/skill.yaml +++ b/packages/valory/skills/decision_maker_abci/skill.yaml @@ -12,32 +12,35 @@ fingerprint: README.md: bafybeia367zzdwndvlhw27rvnwodytjo3ms7gbc3q7mhrrjqjgfasnk47i __init__.py: bafybeih563ujnigeci2ldzh7hakbau6a222vsed7leg3b7lq32vcn3nm4a behaviours/__init__.py: bafybeih6ddz2ocvm6x6ytvlbcz6oi4snb5ee5xh5h65nq4w2qf7fd7zfky - behaviours/base.py: bafybeiaxgbkrrskfod55lhynd4ttkwrn6qwzugfmmwikzod4ar6pmjmcu4 + behaviours/base.py: bafybeiato4qxnc2kjjdtttvqdna7dp4c5evlb6cus7h6eci7tj73tqnpey behaviours/bet_placement.py: bafybeifwwvvwh4qgf3jkyvza4wfvjv63il2xewsklsjtpyanp23y6hg2aa behaviours/blacklisting.py: bafybeicvespraci44y2dtddy4wi7cdhjuyk6crjs7ztnssm2rcrovha3hm - behaviours/decision_receive.py: bafybeifn4xuv2z3niyhgd35ufncrdpaisw7pd4qkw2vv3cte5koqe2mxqy - behaviours/decision_request.py: bafybeifjlh5cfitjd6wjcvcgoji2bhsi4r5nzpqocotwprmn26eiphlmqq + behaviours/decision_receive.py: bafybeid54jwjs4lulcl2n2w7taxne3wqgsey6ppaidwr2up6bztyf35ghm + behaviours/decision_request.py: bafybeidlyl2ojmpfs2zkewoacraya2cbampo4ynqbqaocsoq7v2nif3ahi behaviours/handle_failed_tx.py: bafybeidxpc6u575ymct5tdwutvzov6zqfdoio5irgldn3fw7q3lg36mmxm - behaviours/reedem.py: bafybeidrk7lauummzwygtzc7hmpimlgnd7haia6lmm57z5spfdwu33rlbm - behaviours/round_behaviour.py: bafybeifk5utwuaneima4rdeow7tcpbe6hcc2utlzxcw3w7vsm5zw7zpamm + behaviours/reedem.py: bafybeigzsx4wyov3ehfvdjmo2d7yimss4p7mbkopkqyr4gryxpa5rpv6ku + behaviours/round_behaviour.py: bafybeig4tdktyu6hapoqymnxh2bgpds547st6a44heue657wkctwe4gjvm behaviours/sampling.py: bafybeiadikynvkaofbko72jc45xthhmmjfmlkpgramormhxwk5u47rnwdu + behaviours/tool_selection.py: bafybeidd7jmauc6edgt7caxylanfdz3ucb2qzsndszlxv7an4lohe2waja dialogues.py: bafybeigpwuzku3we7axmxeamg7vn656maww6emuztau5pg3ebsoquyfdqm - fsm_specification.yaml: bafybeigrljw66oxyvn5wqecfgkcx7ozkjg7xuv75zcjmo25fft37qyed6y + fsm_specification.yaml: bafybeifnob3ceim2mj7lqagtnpwqjqqxs5eg3oiwc73gwm6x5i2dvvlcya handlers.py: bafybeihj33szgrcxnpd73s4nvluyxwwsvhjum2cuq3ilhhe6vfola3k7vy - models.py: bafybeibqou3ryuszu2vbwdp5b7fkj5oxmflgh3z3a7tuajbdxgzdolgmee - payloads.py: bafybeifbnyviargcj5w5kbuuvc3o4y5sdogtuynd2b4ca4xsfbi3cqcwlm - redeem_info.py: bafybeic7de4hrsgjmxbjht5ihasm5t7bykuonei5xxhpf3lpzq35fuxy74 - rounds.py: bafybeihpstybessozkb3hjxhf3gvf323zw4d575ihmxrsuzcyhqtbsruoq + models.py: bafybeie6ynq37isn4itspkj2eka6r2wwsok3ofdve6iipw5nwjimmzblzu + payloads.py: bafybeic4iz6uxinqpaxnefkadnzaox23y7k57zawnnkeovplih36v5cchy + policy.py: bafybeiftviqwq6lapfxj6ykxyh64z72vauqrgmsoho7zo2lvsdvu32kw3m + redeem_info.py: bafybeihtbundd75a4wdk2d23smvdjlh7fsv42ff2cwwuwgkyyxjciobwca + rounds.py: bafybeihopxmhzrpipc6r5x2vqf2tcixzuf5xdpqfsr7gr3n756n3ssft5q states/__init__.py: bafybeid23llnyp6j257dluxmrnztugo5llsrog7kua53hllyktz4dqhqoy - states/base.py: bafybeif42mqu6wu55iyjyqxto3poyta22gdsswgtus55lo4qpmv74wvlmm + states/base.py: bafybeibx3kn2b3rovyiowjzpwhspjdbzyfroequg7zsjqsbdh5cyowu72a states/bet_placement.py: bafybeibalhxhp2c4oljmiwqi6ds3g36fgtabmf42mb5sgq6z22znrcbhda states/blacklisting.py: bafybeiao747i4z7owk6dmwfuzdijag55m3ryj3nowfoggvczpgk3koza44 states/decision_receive.py: bafybeifm3oyq2aji7f5yag6wpe4vr3ivi74pybdsk2jvmziiidx5nt7t4a states/decision_request.py: bafybeic7otc3hjb753svbmur3yyk6szahc25yii3x4w4vcnpfz6jwvacuu states/final_states.py: bafybeidiwhuyd5zm2cq7vhv2owcrxdpm7fnvn3db6p6tql4jz5hgpalflu states/handle_failed_tx.py: bafybeihewm2vernvhktuorljdupjqcg2p5vs6wvsira2d62wkoyo5xlzjm - states/redeem.py: bafybeifl7qgs2xvm4nykloec5tq47sriqah3dzahv3gppvgtrrxzw5yyyq + states/redeem.py: bafybeib2y6v3vuvw3upjz75ie7j2bkhclwzp7j77esunabjatdtmdvzqlm states/sampling.py: bafybeidnvdogjlthjfe7jpaiuezm3xydrbxxukyoss4gx6t5fdin52rsta + states/tool_selection.py: bafybeiaaijv6dukp3bmsptcwkcmumc6wu6ztzkvaqzsqqjbfn4ozgyuykq fingerprint_ignore_patterns: [] connections: [] contracts: @@ -45,15 +48,16 @@ contracts: - valory/market_maker:0.1.0:bafybeiftimqgvrbval2lxp7au6y72amioo4gtcdth2dflrbwa47i6opyb4 - valory/erc20:0.1.0:bafybeifjwr6rwklgg2uk2zkfysn55qqy7dfi4jx7sek6lzdup37fynhpxe - valory/multisend:0.1.0:bafybeie7m7pjbnw7cccpbvmbgkut24dtlt4cgvug3tbac7gej37xvwbv3a -- valory/mech:0.1.0:bafybeie753wdqks6k4x5fqlpo7tgll2avutjcaodpwlptqvzefsi5xbvai +- valory/mech:0.1.0:bafybeiehjnwd63xp6ttfsskhxsphnvpjpwrfqzfltjvqn6mjqkemoo2qge - valory/conditional_tokens:0.1.0:bafybeicxwjdbmjajgr5rsmadtkxxwmcm42r2htef3tvng73uzib4hmb6qa - valory/realitio:0.1.0:bafybeicdgm2a7evjw6szcpo3uaam5mzd6axtevtzwvejr6uaeymbg437da - valory/realitio_proxy:0.1.0:bafybeibvndq6756qck7forgeavhdbn6ykgqs2ufyg7n5g6qdfpveatxuwy +- valory/agent_registry:0.1.0:bafybeid3knh7d7uzvtkbdg7xxdjajjb3lhusxju46iydkt5p4wklc4gz5e protocols: - valory/contract_api:1.0.0:bafybeiasywsvax45qmugus5kxogejj66c5taen27h4voriodz7rgushtqa skills: - valory/abstract_round_abci:0.1.0:bafybeif3cqkks5qx3lqi6nwwhebcirhazt2vidw3sueeqsyxvjeszjt3om -- valory/market_manager_abci:0.1.0:bafybeicqrgxbf2pocfh7332qzhcshwsarpwjkj3zroveklsrovozcppsvq +- valory/market_manager_abci:0.1.0:bafybeig223xrxbtfx5adwhc7m6rpdbevsqm5osfq66oijucs2gzn4hehsm - valory/transaction_settlement_abci:0.1.0:bafybeiglsnh2hvfau5gab7requh34k4sbqwbjvrhhqjpes4hakcwq46cpi behaviours: main: @@ -136,6 +140,7 @@ models: round_timeout_seconds: 350.0 service_id: decision_maker service_registry_address: null + agent_registry_address: null setup: all_participants: - '0x0000000000000000000000000000000000000000' @@ -156,7 +161,6 @@ models: tx_timeout: 10.0 use_termination: false mech_agent_address: '0xff82123dfb52ab75c417195c5fdb87630145ae81' - mech_tool: prediction-online bet_amount_per_threshold: 0.0: 0 0.1: 0 @@ -181,6 +185,16 @@ models: realitio_address: '0x79e32aE03fb27B07C89c0c568F80287C01ca2E57' redeeming_batch_size: 5 slippage: 0.01 + policy_epsilon: 0.1 + irrelevant_tools: + - openai-text-davinci-002 + - openai-text-davinci-003 + - openai-gpt-3.5-turbo + - openai-gpt-4 + - stabilityai-stable-diffusion-v1-5 + - stabilityai-stable-diffusion-xl-beta-v2-2-2 + - stabilityai-stable-diffusion-512-v2-1 + - stabilityai-stable-diffusion-768-v2-1 class_name: DecisionMakerParams mech_response: args: @@ -194,6 +208,18 @@ models: retries: 5 url: '' class_name: MechResponseSpecs + agent_tools: + args: + api_id: agent_tools + headers: + Content-Type: application/json + method: GET + parameters: {} + response_key: tools + response_type: list + retries: 5 + url: '' + class_name: AgentToolsSpecs requests: args: {} class_name: Requests diff --git a/packages/valory/skills/decision_maker_abci/states/base.py b/packages/valory/skills/decision_maker_abci/states/base.py index bb7d3a87f..b84092b7d 100644 --- a/packages/valory/skills/decision_maker_abci/states/base.py +++ b/packages/valory/skills/decision_maker_abci/states/base.py @@ -19,8 +19,9 @@ """This module contains the base functionality for the rounds of the decision-making abci app.""" +import json from enum import Enum -from typing import Optional, Tuple +from typing import Dict, List, Optional, Tuple from packages.valory.skills.abstract_round_abci.base import ( CollectSameUntilThresholdRound, @@ -28,6 +29,7 @@ get_name, ) from packages.valory.skills.decision_maker_abci.payloads import MultisigTxPayload +from packages.valory.skills.decision_maker_abci.policy import EGreedyPolicy from packages.valory.skills.market_manager_abci.bets import Bet from packages.valory.skills.market_manager_abci.rounds import ( SynchronizedData as MarketManagerSyncedData, @@ -75,6 +77,38 @@ def mech_price(self) -> int: """Get the mech's request price.""" return int(self.db.get_strict("mech_price")) + @property + def available_mech_tools(self) -> List[str]: + """Get all the available mech tools.""" + tools = self.db.get_strict("available_mech_tools") + return json.loads(tools) + + @property + def policy(self) -> EGreedyPolicy: + """Get the policy.""" + policy = self.db.get_strict("policy") + return EGreedyPolicy.deserialize(policy) + + @property + def mech_tool_idx(self) -> int: + """Get the mech tool's index.""" + return int(self.db.get_strict("mech_tool_idx")) + + @property + def mech_tool(self) -> str: + """Get the selected mech tool.""" + try: + return self.available_mech_tools[self.mech_tool_idx] + except IndexError as exc: + error = f"{self.mech_tool_idx=} is not available in {self.available_mech_tools=}." + raise IndexError(error) from exc + + @property + def utilized_tools(self) -> Dict[str, int]: + """Get a mapping of the utilized tools' indexes for each transaction.""" + tools = str(self.db.get_strict("utilized_tools")) + return json.loads(tools) + @property def vote(self) -> Optional[int]: """Get the bet's vote index.""" diff --git a/packages/valory/skills/decision_maker_abci/states/redeem.py b/packages/valory/skills/decision_maker_abci/states/redeem.py index 3d7e0e651..d222a2249 100644 --- a/packages/valory/skills/decision_maker_abci/states/redeem.py +++ b/packages/valory/skills/decision_maker_abci/states/redeem.py @@ -19,8 +19,16 @@ """This module contains the redeem state of the decision-making abci app.""" +from typing import Type + +from packages.valory.skills.abstract_round_abci.base import get_name +from packages.valory.skills.decision_maker_abci.payloads import ( + MultisigTxPayload, + RedeemPayload, +) from packages.valory.skills.decision_maker_abci.states.base import ( Event, + SynchronizedData, TxPreparationRound, ) @@ -28,4 +36,9 @@ class RedeemRound(TxPreparationRound): """A round in which the agents prepare a tx to redeem the winnings.""" + payload_class: Type[MultisigTxPayload] = RedeemPayload + selection_key = TxPreparationRound.selection_key + ( + get_name(SynchronizedData.policy), + get_name(SynchronizedData.utilized_tools), + ) none_event = Event.NO_REDEEMING diff --git a/packages/valory/skills/decision_maker_abci/states/tool_selection.py b/packages/valory/skills/decision_maker_abci/states/tool_selection.py new file mode 100644 index 000000000..ff65aa3ff --- /dev/null +++ b/packages/valory/skills/decision_maker_abci/states/tool_selection.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 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 tool selection state of the decision-making abci app.""" + +from packages.valory.skills.abstract_round_abci.base import ( + CollectSameUntilThresholdRound, + get_name, +) +from packages.valory.skills.decision_maker_abci.payloads import ToolSelectionPayload +from packages.valory.skills.decision_maker_abci.states.base import ( + Event, + SynchronizedData, +) + + +class ToolSelectionRound(CollectSameUntilThresholdRound): + """A round for selecting a Mech tool.""" + + payload_class = ToolSelectionPayload + synchronized_data_class = SynchronizedData + done_event = Event.DONE + none_event = Event.NONE + no_majority_event = Event.NO_MAJORITY + selection_key = ( + get_name(SynchronizedData.available_mech_tools), + get_name(SynchronizedData.policy), + get_name(SynchronizedData.utilized_tools), + get_name(SynchronizedData.mech_tool_idx), + ) + collection_key = get_name(SynchronizedData.participant_to_selection) diff --git a/packages/valory/skills/market_manager_abci/graph_tooling/queries/omen.py b/packages/valory/skills/market_manager_abci/graph_tooling/queries/omen.py index 65b9cccb0..3f18fc881 100644 --- a/packages/valory/skills/market_manager_abci/graph_tooling/queries/omen.py +++ b/packages/valory/skills/market_manager_abci/graph_tooling/queries/omen.py @@ -83,17 +83,13 @@ question { id data - answers { - id - answer - bondAggregate - } } templateId } outcomeIndex outcomeTokenMarginalPrice outcomeTokensTraded + transactionHash } } """ diff --git a/packages/valory/skills/market_manager_abci/skill.yaml b/packages/valory/skills/market_manager_abci/skill.yaml index 09b1ec6bf..d160e53ca 100644 --- a/packages/valory/skills/market_manager_abci/skill.yaml +++ b/packages/valory/skills/market_manager_abci/skill.yaml @@ -15,7 +15,7 @@ fingerprint: graph_tooling/__init__.py: bafybeigzo7nhbzafyq3fuhrlewksjvmzttiuk4vonrggtjtph4rw4ncpk4 graph_tooling/queries/__init__.py: bafybeihbybnl53i7k57ql5ujt5ru5n2eg324jfndh4lcnm4fk52mwbkjda graph_tooling/queries/network.py: bafybeigeq72ys2nrjqspj2uacaudrgljrne5a3o5jvzsktldxdq6m2xmeu - graph_tooling/queries/omen.py: bafybeiajk65gvqkxvxekywqqy2kob3vobjsealqlyxis3z6mpwhyng7hh4 + graph_tooling/queries/omen.py: bafybeicatte7cinlzcmubkoyne7fgvuedimvotf4pvhacozsy7ndftmmdy graph_tooling/requests.py: bafybeicv7hdo4a56pqteaxoxi5tskfbb34u2ajmhu7canoco3mi3jv6fmy handlers.py: bafybeihot2i2yvfkz2gcowvt66wdu6tkjbmv7hsmc4jzt4reqeaiuphbtu models.py: bafybeiaplszooak63fo3i6agaoyol4tpof4q4tvoj4j6f2cr2corajnl3a diff --git a/packages/valory/skills/trader_abci/fsm_specification.yaml b/packages/valory/skills/trader_abci/fsm_specification.yaml index a9e12a68c..d550e79ea 100644 --- a/packages/valory/skills/trader_abci/fsm_specification.yaml +++ b/packages/valory/skills/trader_abci/fsm_specification.yaml @@ -60,6 +60,7 @@ states: - SelectKeeperTransactionSubmissionBAfterTimeoutRound - SelectKeeperTransactionSubmissionBRound - SynchronizeLateMessagesRound +- ToolSelectionRound - UpdateBetsRound - ValidateTransactionRound transition_func: @@ -130,7 +131,7 @@ transition_func: (ResetRound, DONE): RandomnessTransactionSubmissionRound (ResetRound, NO_MAJORITY): HandleFailedTxRound (ResetRound, RESET_TIMEOUT): HandleFailedTxRound - (SamplingRound, DONE): DecisionRequestRound + (SamplingRound, DONE): ToolSelectionRound (SamplingRound, NONE): RedeemRound (SamplingRound, NO_MAJORITY): SamplingRound (SamplingRound, ROUND_TIMEOUT): SamplingRound @@ -152,6 +153,10 @@ transition_func: (SynchronizeLateMessagesRound, NONE): SelectKeeperTransactionSubmissionBRound (SynchronizeLateMessagesRound, ROUND_TIMEOUT): SynchronizeLateMessagesRound (SynchronizeLateMessagesRound, SUSPICIOUS_ACTIVITY): HandleFailedTxRound + (ToolSelectionRound, DONE): DecisionRequestRound + (ToolSelectionRound, NONE): ToolSelectionRound + (ToolSelectionRound, NO_MAJORITY): ToolSelectionRound + (ToolSelectionRound, ROUND_TIMEOUT): ToolSelectionRound (UpdateBetsRound, DONE): SamplingRound (UpdateBetsRound, FETCH_ERROR): ResetAndPauseRound (UpdateBetsRound, NO_MAJORITY): UpdateBetsRound diff --git a/packages/valory/skills/trader_abci/models.py b/packages/valory/skills/trader_abci/models.py index f5606ffeb..373113b77 100644 --- a/packages/valory/skills/trader_abci/models.py +++ b/packages/valory/skills/trader_abci/models.py @@ -29,6 +29,9 @@ from packages.valory.skills.abstract_round_abci.models import ( SharedState as BaseSharedState, ) +from packages.valory.skills.decision_maker_abci.models import ( + AgentToolsSpecs as DecisionMakerAgentToolsSpecs, +) from packages.valory.skills.decision_maker_abci.models import DecisionMakerParams from packages.valory.skills.decision_maker_abci.models import ( MechResponseSpecs as DecisionMakerMechResponseSpecs, @@ -68,6 +71,7 @@ OmenSubgraph = MarketManagerOmenSubgraph NetworkSubgraph = MarketManagerNetworkSubgraph MechResponseSpecs = DecisionMakerMechResponseSpecs +AgentToolsSpecs = DecisionMakerAgentToolsSpecs MARGIN = 5 diff --git a/packages/valory/skills/trader_abci/skill.yaml b/packages/valory/skills/trader_abci/skill.yaml index f0218ec92..805759eaf 100644 --- a/packages/valory/skills/trader_abci/skill.yaml +++ b/packages/valory/skills/trader_abci/skill.yaml @@ -11,9 +11,9 @@ fingerprint: behaviours.py: bafybeigwadq27e4cnklboorhitwzzve4xkcgjdu2upplbbweuqyl52fj3q composition.py: bafybeie45dgneoggyavgdtswcygvz5o3klmtqf57zoxqnxrtneruutqevi dialogues.py: bafybeiebofyykseqp3fmif36cqmmyf3k7d2zbocpl6t6wnlpv4szghrxbm - fsm_specification.yaml: bafybeiasu522aq3xthvuyvajpvzxy33nu6l4esuyl2xmkslckldcomwfzu + fsm_specification.yaml: bafybeiaomt3gscv4pvxczc4scu6q6laza6bqhpvfi2bfiq37vksuchhqiy handlers.py: bafybeicamc6vmozij5dwvkxmbxjazsgf3sacojhstbjtq7vfggszxugvey - models.py: bafybeih26gyqv24lc2mlz3kbdsifip3zlac3owcpqlyi7hg6du6y6ojdda + models.py: bafybeifj5y7qcoac72woe53zaz2lopkqir2472bbey3ypsqmprjmljms7i fingerprint_ignore_patterns: [] connections: [] contracts: [] @@ -24,9 +24,9 @@ skills: - valory/reset_pause_abci:0.1.0:bafybeifoihgilpfr76hc5skzspm6qehkwivx7ld2cy3veipcsi4gr2c7na - valory/transaction_settlement_abci:0.1.0:bafybeiglsnh2hvfau5gab7requh34k4sbqwbjvrhhqjpes4hakcwq46cpi - valory/termination_abci:0.1.0:bafybeigcsls72uosoui2y5ppmnvsljjhnxakkeh3fdohklcg66aqq4g7xu -- valory/market_manager_abci:0.1.0:bafybeicqrgxbf2pocfh7332qzhcshwsarpwjkj3zroveklsrovozcppsvq -- valory/decision_maker_abci:0.1.0:bafybeihwjudh7pngsgflbrfe2kcvzkaq2edl5j3l3wb463eeagcwpaluay -- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeiab2iz65fsus7h3kk5j3unw6guzvtpfe6ytrcmayay5x2phqsxdlu +- valory/market_manager_abci:0.1.0:bafybeig223xrxbtfx5adwhc7m6rpdbevsqm5osfq66oijucs2gzn4hehsm +- valory/decision_maker_abci:0.1.0:bafybeieqyd5jek55q57lg77hey3oapppoosaphhyxxlulx52gg2ahkqdba +- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeidel3rxm55y2qqewhmwroybs5j7t6ma6awmxbo7xjv3jvhmb6dv7m behaviours: main: args: {} @@ -118,6 +118,7 @@ models: round_timeout_seconds: 350.0 service_id: trader service_registry_address: null + agent_registry_address: null setup: all_participants: - '0x0000000000000000000000000000000000000000' @@ -143,7 +144,6 @@ models: average_block_time: 5 abt_error_mult: 5 mech_agent_address: '0xff82123dfb52ab75c417195c5fdb87630145ae81' - mech_tool: prediction-online bet_amount_per_threshold: 0.0: 0 0.1: 0 @@ -169,6 +169,16 @@ models: redeeming_batch_size: 5 slippage: 0.01 redeem_margin_days: 15 + policy_epsilon: 0.1 + irrelevant_tools: + - openai-text-davinci-002 + - openai-text-davinci-003 + - openai-gpt-3.5-turbo + - openai-gpt-4 + - stabilityai-stable-diffusion-v1-5 + - stabilityai-stable-diffusion-xl-beta-v2-2-2 + - stabilityai-stable-diffusion-512-v2-1 + - stabilityai-stable-diffusion-768-v2-1 class_name: TraderParams network_subgraph: args: @@ -218,6 +228,18 @@ models: retries: 5 url: '' class_name: MechResponseSpecs + agent_tools: + args: + api_id: agent_tools + headers: + Content-Type: application/json + method: GET + parameters: {} + response_key: tools + response_type: list + retries: 5 + url: '' + class_name: AgentToolsSpecs requests: args: {} class_name: Requests diff --git a/packages/valory/skills/tx_settlement_multiplexer_abci/rounds.py b/packages/valory/skills/tx_settlement_multiplexer_abci/rounds.py index ca274730a..a7303fbc6 100644 --- a/packages/valory/skills/tx_settlement_multiplexer_abci/rounds.py +++ b/packages/valory/skills/tx_settlement_multiplexer_abci/rounds.py @@ -19,6 +19,7 @@ """This package contains the rounds of `TxSettlementMultiplexerAbciApp`.""" +import json from enum import Enum from typing import Any, Dict, Optional, Set, Tuple @@ -74,6 +75,14 @@ def end_block(self) -> Optional[Tuple[BaseSynchronizedData, Enum]]: synced_data = SynchronizedData(self.synchronized_data.db) event = submitter_to_event.get(synced_data.tx_submitter, Event.UNRECOGNIZED) + + # if a bet was just placed, edit the utilized tools mapping + if event == Event.BET_PLACEMENT_DONE: + utilized_tools = synced_data.utilized_tools + utilized_tools[synced_data.final_tx_hash] = synced_data.mech_tool_idx + tools_update = json.dumps(utilized_tools, sort_keys=True) + self.synchronized_data.update(utilized_tools=tools_update) + return synced_data, event diff --git a/packages/valory/skills/tx_settlement_multiplexer_abci/skill.yaml b/packages/valory/skills/tx_settlement_multiplexer_abci/skill.yaml index cf3154e26..9d2c0043d 100644 --- a/packages/valory/skills/tx_settlement_multiplexer_abci/skill.yaml +++ b/packages/valory/skills/tx_settlement_multiplexer_abci/skill.yaml @@ -13,14 +13,14 @@ fingerprint: fsm_specification.yaml: bafybeibeas5ovngfhfox4dkkwdvhogpuzkmwj6r33ez2xxvvmvmesa3xvm handlers.py: bafybeiafbqr7ojfcbwohvee7x4zzswad3ymfrrbjlfz7uuuttmn3qdfs6q models.py: bafybeiahojnn52s762zitwx6k5s4ef5qw7hwjf3orlklqwuz3zi7k2o7bi - rounds.py: bafybeifotgp5zr6vrgfhursm7dwkju74qdrruw7ui7zmbl5t34om4fnapa + rounds.py: bafybeigyok6qh5firjs5osarsmtcugqhcibishulr6zzdfsnesm6jcxqqa fingerprint_ignore_patterns: [] connections: [] contracts: [] protocols: [] skills: - valory/abstract_round_abci:0.1.0:bafybeif3cqkks5qx3lqi6nwwhebcirhazt2vidw3sueeqsyxvjeszjt3om -- valory/decision_maker_abci:0.1.0:bafybeihwjudh7pngsgflbrfe2kcvzkaq2edl5j3l3wb463eeagcwpaluay +- valory/decision_maker_abci:0.1.0:bafybeieqyd5jek55q57lg77hey3oapppoosaphhyxxlulx52gg2ahkqdba behaviours: main: args: {} diff --git a/poetry.lock b/poetry.lock index f567718c6..c9bd55e16 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand. [[package]] name = "aiohttp" @@ -2135,31 +2135,37 @@ files = [ [[package]] name = "pandas" -version = "2.1.0" +version = "2.1.1" description = "Powerful data structures for data analysis, time series, and statistics" category = "main" optional = false python-versions = ">=3.9" files = [ - {file = "pandas-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:40dd20439ff94f1b2ed55b393ecee9cb6f3b08104c2c40b0cb7186a2f0046242"}, - {file = "pandas-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d4f38e4fedeba580285eaac7ede4f686c6701a9e618d8a857b138a126d067f2f"}, - {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e6a0fe052cf27ceb29be9429428b4918f3740e37ff185658f40d8702f0b3e09"}, - {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d81e1813191070440d4c7a413cb673052b3b4a984ffd86b8dd468c45742d3cc"}, - {file = "pandas-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eb20252720b1cc1b7d0b2879ffc7e0542dd568f24d7c4b2347cb035206936421"}, - {file = "pandas-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:38f74ef7ebc0ffb43b3d633e23d74882bce7e27bfa09607f3c5d3e03ffd9a4a5"}, - {file = "pandas-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cda72cc8c4761c8f1d97b169661f23a86b16fdb240bdc341173aee17e4d6cedd"}, - {file = "pandas-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d97daeac0db8c993420b10da4f5f5b39b01fc9ca689a17844e07c0a35ac96b4b"}, - {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c58b1113892e0c8078f006a167cc210a92bdae23322bb4614f2f0b7a4b510f"}, - {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:629124923bcf798965b054a540f9ccdfd60f71361255c81fa1ecd94a904b9dd3"}, - {file = "pandas-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:70cf866af3ab346a10debba8ea78077cf3a8cd14bd5e4bed3d41555a3280041c"}, - {file = "pandas-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d53c8c1001f6a192ff1de1efe03b31a423d0eee2e9e855e69d004308e046e694"}, - {file = "pandas-2.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86f100b3876b8c6d1a2c66207288ead435dc71041ee4aea789e55ef0e06408cb"}, - {file = "pandas-2.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f330845ad21c11db51e02d8d69acc9035edfd1116926ff7245c7215db57957"}, - {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9a6ccf0963db88f9b12df6720e55f337447aea217f426a22d71f4213a3099a6"}, - {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99e678180bc59b0c9443314297bddce4ad35727a1a2656dbe585fd78710b3b9"}, - {file = "pandas-2.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b31da36d376d50a1a492efb18097b9101bdbd8b3fbb3f49006e02d4495d4c644"}, - {file = "pandas-2.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0164b85937707ec7f70b34a6c3a578dbf0f50787f910f21ca3b26a7fd3363437"}, - {file = "pandas-2.1.0.tar.gz", hash = "sha256:62c24c7fc59e42b775ce0679cfa7b14a5f9bfb7643cfbe708c960699e05fb918"}, + {file = "pandas-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58d997dbee0d4b64f3cb881a24f918b5f25dd64ddf31f467bb9b67ae4c63a1e4"}, + {file = "pandas-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02304e11582c5d090e5a52aec726f31fe3f42895d6bfc1f28738f9b64b6f0614"}, + {file = "pandas-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffa8f0966de2c22de408d0e322db2faed6f6e74265aa0856f3824813cf124363"}, + {file = "pandas-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1f84c144dee086fe4f04a472b5cd51e680f061adf75c1ae4fc3a9275560f8f4"}, + {file = "pandas-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:75ce97667d06d69396d72be074f0556698c7f662029322027c226fd7a26965cb"}, + {file = "pandas-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:4c3f32fd7c4dccd035f71734df39231ac1a6ff95e8bdab8d891167197b7018d2"}, + {file = "pandas-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e2959720b70e106bb1d8b6eadd8ecd7c8e99ccdbe03ee03260877184bb2877d"}, + {file = "pandas-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:25e8474a8eb258e391e30c288eecec565bfed3e026f312b0cbd709a63906b6f8"}, + {file = "pandas-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8bd1685556f3374520466998929bade3076aeae77c3e67ada5ed2b90b4de7f0"}, + {file = "pandas-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc3657869c7902810f32bd072f0740487f9e030c1a3ab03e0af093db35a9d14e"}, + {file = "pandas-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:05674536bd477af36aa2effd4ec8f71b92234ce0cc174de34fd21e2ee99adbc2"}, + {file = "pandas-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:b407381258a667df49d58a1b637be33e514b07f9285feb27769cedb3ab3d0b3a"}, + {file = "pandas-2.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c747793c4e9dcece7bb20156179529898abf505fe32cb40c4052107a3c620b49"}, + {file = "pandas-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3bcad1e6fb34b727b016775bea407311f7721db87e5b409e6542f4546a4951ea"}, + {file = "pandas-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5ec7740f9ccb90aec64edd71434711f58ee0ea7f5ed4ac48be11cfa9abf7317"}, + {file = "pandas-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29deb61de5a8a93bdd033df328441a79fcf8dd3c12d5ed0b41a395eef9cd76f0"}, + {file = "pandas-2.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4f99bebf19b7e03cf80a4e770a3e65eee9dd4e2679039f542d7c1ace7b7b1daa"}, + {file = "pandas-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:84e7e910096416adec68075dc87b986ff202920fb8704e6d9c8c9897fe7332d6"}, + {file = "pandas-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:366da7b0e540d1b908886d4feb3d951f2f1e572e655c1160f5fde28ad4abb750"}, + {file = "pandas-2.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e50e72b667415a816ac27dfcfe686dc5a0b02202e06196b943d54c4f9c7693e"}, + {file = "pandas-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc1ab6a25da197f03ebe6d8fa17273126120874386b4ac11c1d687df288542dd"}, + {file = "pandas-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0dbfea0dd3901ad4ce2306575c54348d98499c95be01b8d885a2737fe4d7a98"}, + {file = "pandas-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0489b0e6aa3d907e909aef92975edae89b1ee1654db5eafb9be633b0124abe97"}, + {file = "pandas-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:4cdb0fab0400c2cb46dafcf1a0fe084c8bb2480a1fa8d81e19d15e12e6d4ded2"}, + {file = "pandas-2.1.1.tar.gz", hash = "sha256:fecb198dc389429be557cde50a2d46da8434a17fe37d7d41ff102e3987fd947b"}, ] [package.dependencies] @@ -3612,4 +3618,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.10, <3.11" -content-hash = "ca2f51408defa2cc5d1c39096101ceb6fef99a50232def53db4827bdc5e52eac" +content-hash = "988804e9621ec781449dac06578beab62eb50876a73f2e3e47a723d67b1d0bc3" diff --git a/pyproject.toml b/pyproject.toml index 8816b4d94..a8569d272 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ eth-abi = "==4.0.0" pycryptodome = "==3.18.0" pytest = "==7.2.1" urllib3 = "==1.26.16" +jsonschema = "<=4.19.0,>=4.16.0" [tool.poetry.group.dev.dependencies.tomte] version = "==0.2.12" diff --git a/tox.ini b/tox.ini index 47a4de9c5..0b5f0da39 100644 --- a/tox.ini +++ b/tox.ini @@ -51,6 +51,7 @@ deps = pycryptodome==3.18.0 pytest==7.2.1 urllib3==1.26.16 + jsonschema<=4.19.0,>=4.16.0 [testenv] basepython = python3 @@ -120,7 +121,7 @@ commands = [testenv:check-dependencies] skipsdist = True usedevelop = True -commands = +commands = autonomy packages sync {toxinidir}/scripts/check_dependencies.py @@ -363,6 +364,9 @@ ignore_missing_imports = True [mypy-hexbytes.*] ignore_missing_imports = True +[mypy-autonomy.*] +ignore_missing_imports = True + [darglint] docstring_style=sphinx strictness=short