Skip to content

Commit

Permalink
Showing 36 changed files with 1,958 additions and 132 deletions.
8 changes: 0 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -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}`.
17 changes: 9 additions & 8 deletions packages/packages.json
Original file line number Diff line number Diff line change
@@ -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",
17 changes: 11 additions & 6 deletions packages/valory/agents/trader/aea-config.yaml
Original file line number Diff line number Diff line change
@@ -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
20 changes: 20 additions & 0 deletions packages/valory/contracts/agent_registry/__init__.py
Original file line number Diff line number Diff line change
@@ -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."""
1,046 changes: 1,046 additions & 0 deletions packages/valory/contracts/agent_registry/build/AgentRegistry.json

Large diffs are not rendered by default.

64 changes: 64 additions & 0 deletions packages/valory/contracts/agent_registry/contract.py
Original file line number Diff line number Diff line change
@@ -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())
23 changes: 23 additions & 0 deletions packages/valory/contracts/agent_registry/contract.yaml
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions packages/valory/contracts/mech/contract.py
Original file line number Diff line number Diff line change
@@ -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)
2 changes: 1 addition & 1 deletion packages/valory/contracts/mech/contract.yaml
Original file line number Diff line number Diff line change
@@ -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
30 changes: 25 additions & 5 deletions packages/valory/services/trader/service.yaml
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions packages/valory/skills/decision_maker_abci/behaviours/base.py
Original file line number Diff line number Diff line change
@@ -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."""
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -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)

51 changes: 45 additions & 6 deletions packages/valory/skills/decision_maker_abci/behaviours/reedem.py
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -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
12 changes: 10 additions & 2 deletions packages/valory/skills/decision_maker_abci/models.py
Original file line number Diff line number Diff line change
@@ -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."""
18 changes: 18 additions & 0 deletions packages/valory/skills/decision_maker_abci/payloads.py
Original file line number Diff line number Diff line change
@@ -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]
137 changes: 137 additions & 0 deletions packages/valory/skills/decision_maker_abci/policy.py
Original file line number Diff line number Diff line change
@@ -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)
15 changes: 9 additions & 6 deletions packages/valory/skills/decision_maker_abci/redeem_info.py
Original file line number Diff line number Diff line change
@@ -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
83 changes: 52 additions & 31 deletions packages/valory/skills/decision_maker_abci/rounds.py
Original file line number Diff line number Diff line change
@@ -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,
56 changes: 41 additions & 15 deletions packages/valory/skills/decision_maker_abci/skill.yaml
Original file line number Diff line number Diff line change
@@ -12,48 +12,52 @@ 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:
- valory/gnosis_safe:0.1.0:bafybeih7gkbdtnhkc3i53mbsj7bcihqa7xau6ewsnew4kkul7phwb4ucjm
- 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
36 changes: 35 additions & 1 deletion packages/valory/skills/decision_maker_abci/states/base.py
Original file line number Diff line number Diff line change
@@ -19,15 +19,17 @@

"""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,
DeserializedCollection,
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."""
13 changes: 13 additions & 0 deletions packages/valory/skills/decision_maker_abci/states/redeem.py
Original file line number Diff line number Diff line change
@@ -19,13 +19,26 @@

"""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,
)


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
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -83,17 +83,13 @@
question {
id
data
answers {
id
answer
bondAggregate
}
}
templateId
}
outcomeIndex
outcomeTokenMarginalPrice
outcomeTokensTraded
transactionHash
}
}
"""
2 changes: 1 addition & 1 deletion packages/valory/skills/market_manager_abci/skill.yaml
Original file line number Diff line number Diff line change
@@ -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
7 changes: 6 additions & 1 deletion packages/valory/skills/trader_abci/fsm_specification.yaml
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions packages/valory/skills/trader_abci/models.py
Original file line number Diff line number Diff line change
@@ -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

34 changes: 28 additions & 6 deletions packages/valory/skills/trader_abci/skill.yaml
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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


Original file line number Diff line number Diff line change
@@ -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: {}
50 changes: 28 additions & 22 deletions poetry.lock
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -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"
6 changes: 5 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 5af275f

Please sign in to comment.