prediction-market-agent-tooling 0.48.6__tar.gz → 0.48.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/PKG-INFO +1 -1
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/deploy/agent.py +35 -5
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/data_models.py +4 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/omen/data_models.py +28 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/omen/omen.py +7 -1
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +3 -2
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +22 -44
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +63 -1
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +41 -38
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/pyproject.toml +1 -1
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/README.md +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/depositablewrapper_erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/erc4626.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/omen_thumbnailmapping.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/abis/proxy.abi.json +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/benchmark/utils.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/config.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/deploy/betting_strategy.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/deploy/constants.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/gtypes.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/loggers.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/agent_market.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/categorize.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/manifold/manifold.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/markets.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/metaculus/api.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/metaculus/data_models.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/metaculus/metaculus.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/monitor/markets/manifold.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/monitor/markets/metaculus.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/monitor/markets/omen.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/monitor/markets/polymarket.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/monitor/monitor.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/monitor/monitor_app.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/monitor/monitor_settings.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/py.typed +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/balances.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/cache.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/contract.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/costs.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/gnosis_rpc.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/google.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/image_gen/image_gen.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/image_gen/market_thumbnail_gen.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/langfuse_.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/safe.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/singleton.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/streamlit_user_login.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/tavily_storage/tavily_models.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/tavily_storage/tavily_storage.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/utils.py +0 -0
- {prediction_market_agent_tooling-0.48.6 → prediction_market_agent_tooling-0.48.9}/prediction_market_agent_tooling/tools/web3_utils.py +0 -0
@@ -100,6 +100,10 @@ def initialize_langfuse(enable_langfuse: bool) -> None:
|
|
100
100
|
Decision = Annotated[bool, BeforeValidator(to_boolean_outcome)]
|
101
101
|
|
102
102
|
|
103
|
+
class CantPayForGasError(ValueError):
|
104
|
+
pass
|
105
|
+
|
106
|
+
|
103
107
|
class OutOfFundsError(ValueError):
|
104
108
|
pass
|
105
109
|
|
@@ -337,17 +341,38 @@ class DeployableTraderAgent(DeployableAgent):
|
|
337
341
|
]
|
338
342
|
)
|
339
343
|
|
340
|
-
def check_min_required_balance_to_operate(
|
344
|
+
def check_min_required_balance_to_operate(
|
345
|
+
self,
|
346
|
+
market_type: MarketType,
|
347
|
+
check_for_gas: bool = True,
|
348
|
+
check_for_trades: bool = True,
|
349
|
+
) -> None:
|
341
350
|
api_keys = APIKeys()
|
351
|
+
if (
|
352
|
+
market_type == MarketType.OMEN
|
353
|
+
and check_for_gas
|
354
|
+
and not is_minimum_required_balance(
|
355
|
+
api_keys.public_key,
|
356
|
+
min_required_balance=xdai_type(0.001),
|
357
|
+
sum_wxdai=False,
|
358
|
+
)
|
359
|
+
):
|
360
|
+
raise CantPayForGasError(
|
361
|
+
f"{api_keys.public_key=} doesn't have enough xDai to pay for gas."
|
362
|
+
)
|
342
363
|
if self.min_required_balance_to_operate is None:
|
343
364
|
return
|
344
|
-
if
|
345
|
-
|
346
|
-
|
365
|
+
if (
|
366
|
+
market_type == MarketType.OMEN
|
367
|
+
and check_for_trades
|
368
|
+
and not is_minimum_required_balance(
|
369
|
+
api_keys.bet_from_address,
|
370
|
+
min_required_balance=self.min_required_balance_to_operate,
|
371
|
+
)
|
347
372
|
):
|
348
373
|
raise OutOfFundsError(
|
349
374
|
f"Minimum required balance {self.min_required_balance_to_operate} "
|
350
|
-
f"for agent with address {api_keys.
|
375
|
+
f"for agent with address {api_keys.bet_from_address=} is not met."
|
351
376
|
)
|
352
377
|
|
353
378
|
def have_bet_on_market_since(self, market: AgentMarket, since: timedelta) -> bool:
|
@@ -448,8 +473,13 @@ class DeployableTraderAgent(DeployableAgent):
|
|
448
473
|
"""
|
449
474
|
api_keys = APIKeys()
|
450
475
|
if market_type == MarketType.OMEN:
|
476
|
+
# First, check if we have enough xDai to pay for gas, there is no way of doing anything without it.
|
477
|
+
self.check_min_required_balance_to_operate(
|
478
|
+
market_type, check_for_trades=False
|
479
|
+
)
|
451
480
|
# Omen is specific, because the user (agent) needs to manually withdraw winnings from the market.
|
452
481
|
redeem_from_all_user_positions(api_keys)
|
482
|
+
# After redeeming, check if we have enough xDai to pay for gas and place bets.
|
453
483
|
self.check_min_required_balance_to_operate(market_type)
|
454
484
|
# Exchange wxdai back to xdai if the balance is getting low, so we can keep paying for fees.
|
455
485
|
if self.min_balance_to_keep_in_native_currency is not None:
|
@@ -470,6 +470,8 @@ class RealityQuestion(BaseModel):
|
|
470
470
|
updatedTimestamp: datetime
|
471
471
|
contentHash: HexBytes
|
472
472
|
questionId: HexBytes
|
473
|
+
answerFinalizedTimestamp: datetime
|
474
|
+
currentScheduledFinalizationTimestamp: datetime
|
473
475
|
|
474
476
|
@property
|
475
477
|
def url(self) -> str:
|
@@ -486,6 +488,32 @@ class RealityAnswer(BaseModel):
|
|
486
488
|
createdBlock: int
|
487
489
|
|
488
490
|
|
491
|
+
class RealityResponse(BaseModel):
|
492
|
+
"""
|
493
|
+
This is similar to `RealityAnswer`, but contains additional fields, most importantly `historyHash`.
|
494
|
+
"""
|
495
|
+
|
496
|
+
id: str
|
497
|
+
timestamp: datetime
|
498
|
+
answer: HexBytes
|
499
|
+
isUnrevealed: bool
|
500
|
+
isCommitment: bool
|
501
|
+
bond: Wei
|
502
|
+
user: HexAddress
|
503
|
+
historyHash: HexBytes
|
504
|
+
question: RealityQuestion
|
505
|
+
createdBlock: int
|
506
|
+
revealedBlock: int | None
|
507
|
+
|
508
|
+
@property
|
509
|
+
def bond_xdai(self) -> xDai:
|
510
|
+
return wei_to_xdai(self.bond)
|
511
|
+
|
512
|
+
@property
|
513
|
+
def user_checksummed(self) -> ChecksumAddress:
|
514
|
+
return Web3.to_checksum_address(self.user)
|
515
|
+
|
516
|
+
|
489
517
|
class RealityAnswers(BaseModel):
|
490
518
|
answers: list[RealityAnswer]
|
491
519
|
|
@@ -1047,13 +1047,19 @@ def is_minimum_required_balance(
|
|
1047
1047
|
address: ChecksumAddress,
|
1048
1048
|
min_required_balance: xDai,
|
1049
1049
|
web3: Web3 | None = None,
|
1050
|
+
sum_xdai: bool = True,
|
1051
|
+
sum_wxdai: bool = True,
|
1050
1052
|
) -> bool:
|
1051
1053
|
"""
|
1052
1054
|
Checks if the total balance of xDai and wxDai in the wallet is above the minimum required balance.
|
1053
1055
|
"""
|
1054
1056
|
current_balances = get_balances(address, web3)
|
1055
1057
|
# xDai and wxDai have equal value and can be exchanged for almost no cost, so we can sum them up.
|
1056
|
-
total_balance =
|
1058
|
+
total_balance = 0.0
|
1059
|
+
if sum_xdai:
|
1060
|
+
total_balance += current_balances.xdai
|
1061
|
+
if sum_wxdai:
|
1062
|
+
total_balance += current_balances.wxdai
|
1057
1063
|
return total_balance >= min_required_balance
|
1058
1064
|
|
1059
1065
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
import random
|
3
3
|
import typing as t
|
4
|
-
from datetime import datetime
|
4
|
+
from datetime import datetime, timedelta
|
5
5
|
from enum import Enum
|
6
6
|
|
7
7
|
from web3 import Web3
|
@@ -521,6 +521,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
|
|
521
521
|
language: str,
|
522
522
|
arbitrator: Arbitrator,
|
523
523
|
opening: datetime,
|
524
|
+
timeout: timedelta = timedelta(days=1),
|
524
525
|
nonce: int | None = None,
|
525
526
|
tx_params: t.Optional[TxParams] = None,
|
526
527
|
web3: Web3 | None = None,
|
@@ -547,7 +548,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
|
|
547
548
|
template_id=template_id,
|
548
549
|
question=realitio_question,
|
549
550
|
arbitrator=arbitrator_contract_address,
|
550
|
-
timeout=
|
551
|
+
timeout=int(timeout.total_seconds()),
|
551
552
|
opening_ts=int(opening.timestamp()),
|
552
553
|
nonce=(
|
553
554
|
nonce if nonce is not None else random.randint(0, 1000000)
|
@@ -33,7 +33,6 @@ from prediction_market_agent_tooling.markets.omen.omen_subgraph_handler import (
|
|
33
33
|
from prediction_market_agent_tooling.markets.polymarket.utils import (
|
34
34
|
find_resolution_on_polymarket,
|
35
35
|
)
|
36
|
-
from prediction_market_agent_tooling.tools.utils import check_not_none
|
37
36
|
from prediction_market_agent_tooling.tools.web3_utils import ZERO_BYTES, xdai_to_wei
|
38
37
|
|
39
38
|
|
@@ -42,7 +41,6 @@ def claim_bonds_on_realitio_questions(
|
|
42
41
|
questions: list[RealityQuestion],
|
43
42
|
auto_withdraw: bool,
|
44
43
|
web3: Web3 | None = None,
|
45
|
-
silent_errors: bool = False,
|
46
44
|
) -> list[HexBytes]:
|
47
45
|
claimed_questions: list[HexBytes] = []
|
48
46
|
|
@@ -50,19 +48,10 @@ def claim_bonds_on_realitio_questions(
|
|
50
48
|
logger.info(
|
51
49
|
f"[{idx+1} / {len(questions)}] Claiming bond for {question.questionId=} {question.url=}"
|
52
50
|
)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
claimed_questions.append(question.questionId)
|
58
|
-
except Exception as e:
|
59
|
-
# TODO: This shouldn't be required once `claim_bonds_on_realitio_question` below is fixed.
|
60
|
-
if silent_errors:
|
61
|
-
logger.warning(
|
62
|
-
f"Error while claiming bond for {question.questionId=} {question.url=}: {e}"
|
63
|
-
)
|
64
|
-
else:
|
65
|
-
raise
|
51
|
+
claim_bonds_on_realitio_question(
|
52
|
+
api_keys, question, auto_withdraw=auto_withdraw, web3=web3
|
53
|
+
)
|
54
|
+
claimed_questions.append(question.questionId)
|
66
55
|
|
67
56
|
return claimed_questions
|
68
57
|
|
@@ -77,50 +66,39 @@ def claim_bonds_on_realitio_question(
|
|
77
66
|
realitio_contract = OmenRealitioContract()
|
78
67
|
|
79
68
|
# Get all answers for the question.
|
80
|
-
|
69
|
+
responses = OmenSubgraphHandler().get_responses(question_id=question.questionId)
|
81
70
|
|
82
|
-
|
83
|
-
|
71
|
+
# They need to be processed in order.
|
72
|
+
responses = sorted(responses, key=lambda x: x.timestamp)
|
84
73
|
|
85
|
-
if
|
86
|
-
raise ValueError(f"
|
74
|
+
if not responses:
|
75
|
+
raise ValueError(f"No answers found for {question.questionId.hex()=}")
|
87
76
|
|
88
|
-
if
|
89
|
-
|
90
|
-
# The trouble is, that historyHash is updated after each new answer and the contract holds only the latest one.
|
91
|
-
# So if we have more than 1 answer, we missing the historyHash n-1 of them and this would fail.
|
92
|
-
# You can find how to calculate history hash at https://realitio.github.io/docs/html/contract_explanation.html#answer-history-entries.
|
93
|
-
# At the moment, we support only 1 answer, as for that one answer we will have the hash.
|
94
|
-
raise NotImplementedError()
|
77
|
+
if responses[-1].question.historyHash == ZERO_BYTES:
|
78
|
+
raise ValueError(f"Already claimed {question.questionId.hex()=}.")
|
95
79
|
|
96
|
-
# Logic taken from packages/valory/skills/decision_maker_abci/models.py in `def claim_params`.
|
97
80
|
history_hashes: list[HexBytes] = []
|
98
81
|
addresses: list[ChecksumAddress] = []
|
99
82
|
bonds: list[Wei] = []
|
100
83
|
answers: list[HexBytes] = []
|
101
84
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
85
|
+
# Caller must provide the answer history, in reverse order.
|
86
|
+
# See https://gnosisscan.io/address/0x79e32aE03fb27B07C89c0c568F80287C01ca2E57#code#L625 for the `claimWinnings` logic.
|
87
|
+
reversed_responses = list(reversed(responses))
|
88
|
+
|
89
|
+
for i, response in enumerate(reversed_responses):
|
90
|
+
# second-last-to-first, the hash of each history entry. (Final one should be empty).
|
91
|
+
if i == len(reversed_responses) - 1:
|
106
92
|
history_hashes.append(ZERO_BYTES)
|
107
93
|
else:
|
108
|
-
|
109
|
-
# This is from the original Olas implementation (https://github.com/kongzii/trader/blob/700af475a4538cc3d5d22caf9dec9e9d22d72af1/packages/valory/skills/market_manager_abci/graph_tooling/requests.py#L297),
|
110
|
-
# but it's most probably wrong (see comment above).
|
111
|
-
history_hashes.append(
|
112
|
-
check_not_none(
|
113
|
-
answers_objects[i + 1].question.historyHash,
|
114
|
-
"Shouldn't be None here.",
|
115
|
-
)
|
116
|
-
)
|
94
|
+
history_hashes.append(reversed_responses[i + 1].historyHash)
|
117
95
|
|
118
96
|
# last-to-first, the address of each answerer or commitment sender
|
119
|
-
addresses.append(Web3.to_checksum_address(
|
97
|
+
addresses.append(Web3.to_checksum_address(response.user))
|
120
98
|
# last-to-first, the bond supplied with each answer or commitment
|
121
|
-
bonds.append(
|
99
|
+
bonds.append(response.bond)
|
122
100
|
# last-to-first, each answer supplied, or commitment ID if the answer was supplied with commit->reveal
|
123
|
-
answers.append(
|
101
|
+
answers.append(response.answer)
|
124
102
|
|
125
103
|
realitio_contract.claimWinnings(
|
126
104
|
api_keys=api_keys,
|
@@ -22,6 +22,7 @@ from prediction_market_agent_tooling.markets.omen.data_models import (
|
|
22
22
|
OmenUserPosition,
|
23
23
|
RealityAnswer,
|
24
24
|
RealityQuestion,
|
25
|
+
RealityResponse,
|
25
26
|
)
|
26
27
|
from prediction_market_agent_tooling.markets.omen.omen_contracts import (
|
27
28
|
OmenThumbnailMapping,
|
@@ -118,6 +119,8 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
118
119
|
questions_field.questionId,
|
119
120
|
questions_field.contentHash,
|
120
121
|
questions_field.historyHash,
|
122
|
+
questions_field.answerFinalizedTimestamp,
|
123
|
+
questions_field.currentScheduledFinalizationTimestamp,
|
121
124
|
]
|
122
125
|
|
123
126
|
def _get_fields_for_answers(self, answers_field: FieldPath) -> list[FieldPath]:
|
@@ -130,6 +133,20 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
130
133
|
answers_field.createdBlock,
|
131
134
|
] + self._get_fields_for_reality_questions(answers_field.question)
|
132
135
|
|
136
|
+
def _get_fields_for_responses(self, responses_field: FieldPath) -> list[FieldPath]:
|
137
|
+
return [
|
138
|
+
responses_field.id,
|
139
|
+
responses_field.timestamp,
|
140
|
+
responses_field.answer,
|
141
|
+
responses_field.isUnrevealed,
|
142
|
+
responses_field.isCommitment,
|
143
|
+
responses_field.bond,
|
144
|
+
responses_field.user,
|
145
|
+
responses_field.historyHash,
|
146
|
+
responses_field.createdBlock,
|
147
|
+
responses_field.revealedBlock,
|
148
|
+
] + self._get_fields_for_reality_questions(responses_field.question)
|
149
|
+
|
133
150
|
def _get_fields_for_market_questions(
|
134
151
|
self, questions_field: FieldPath
|
135
152
|
) -> list[FieldPath]:
|
@@ -175,11 +192,13 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
175
192
|
def _build_where_statements(
|
176
193
|
self,
|
177
194
|
creator: t.Optional[HexAddress] = None,
|
195
|
+
creator_in: t.Optional[t.Sequence[HexAddress]] = None,
|
178
196
|
outcomes: list[str] = [OMEN_TRUE_OUTCOME, OMEN_FALSE_OUTCOME],
|
179
197
|
created_after: t.Optional[datetime] = None,
|
180
198
|
opened_before: t.Optional[datetime] = None,
|
181
199
|
opened_after: t.Optional[datetime] = None,
|
182
200
|
finalized_before: t.Optional[datetime] = None,
|
201
|
+
finalized_after: t.Optional[datetime] = None,
|
183
202
|
finalized: bool | None = None,
|
184
203
|
resolved: bool | None = None,
|
185
204
|
liquidity_bigger_than: Wei | None = None,
|
@@ -202,7 +221,10 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
202
221
|
]
|
203
222
|
|
204
223
|
if creator:
|
205
|
-
where_stms["creator"] = creator
|
224
|
+
where_stms["creator"] = creator.lower()
|
225
|
+
|
226
|
+
if creator_in:
|
227
|
+
where_stms["creator_in"] = [x.lower() for x in creator_in]
|
206
228
|
|
207
229
|
if created_after:
|
208
230
|
where_stms["creationTimestamp_gt"] = to_int_timestamp(created_after)
|
@@ -244,6 +266,11 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
244
266
|
finalized_before
|
245
267
|
)
|
246
268
|
|
269
|
+
if finalized_after:
|
270
|
+
where_stms["answerFinalizedTimestamp_gt"] = to_int_timestamp(
|
271
|
+
finalized_after
|
272
|
+
)
|
273
|
+
|
247
274
|
# `excluded_question_titles` can not be an empty list, otherwise the API bugs out and returns nothing.
|
248
275
|
excluded_question_titles = [""]
|
249
276
|
if excluded_questions:
|
@@ -331,9 +358,11 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
331
358
|
opened_before: t.Optional[datetime] = None,
|
332
359
|
opened_after: t.Optional[datetime] = None,
|
333
360
|
finalized_before: t.Optional[datetime] = None,
|
361
|
+
finalized_after: t.Optional[datetime] = None,
|
334
362
|
finalized: bool | None = None,
|
335
363
|
resolved: bool | None = None,
|
336
364
|
creator: t.Optional[HexAddress] = None,
|
365
|
+
creator_in: t.Optional[t.Sequence[HexAddress]] = None,
|
337
366
|
liquidity_bigger_than: Wei | None = None,
|
338
367
|
condition_id_in: list[HexBytes] | None = None,
|
339
368
|
id_in: list[str] | None = None,
|
@@ -353,11 +382,13 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
353
382
|
"""
|
354
383
|
where_stms = self._build_where_statements(
|
355
384
|
creator=creator,
|
385
|
+
creator_in=creator_in,
|
356
386
|
outcomes=outcomes,
|
357
387
|
created_after=created_after,
|
358
388
|
opened_before=opened_before,
|
359
389
|
opened_after=opened_after,
|
360
390
|
finalized_before=finalized_before,
|
391
|
+
finalized_after=finalized_after,
|
361
392
|
finalized=finalized,
|
362
393
|
resolved=resolved,
|
363
394
|
condition_id_in=condition_id_in,
|
@@ -582,6 +613,10 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
582
613
|
user: HexAddress | None = None,
|
583
614
|
claimed: bool | None = None,
|
584
615
|
current_answer_before: datetime | None = None,
|
616
|
+
finalized_before: datetime | None = None,
|
617
|
+
finalized_after: datetime | None = None,
|
618
|
+
id_in: list[str] | None = None,
|
619
|
+
question_id_in: list[HexBytes] | None = None,
|
585
620
|
) -> list[RealityQuestion]:
|
586
621
|
where_stms: dict[str, t.Any] = {}
|
587
622
|
|
@@ -599,6 +634,22 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
599
634
|
current_answer_before
|
600
635
|
)
|
601
636
|
|
637
|
+
if finalized_before is not None:
|
638
|
+
where_stms["answerFinalizedTimestamp_lt"] = to_int_timestamp(
|
639
|
+
finalized_before
|
640
|
+
)
|
641
|
+
|
642
|
+
if finalized_after is not None:
|
643
|
+
where_stms["answerFinalizedTimestamp_gt"] = to_int_timestamp(
|
644
|
+
finalized_after
|
645
|
+
)
|
646
|
+
|
647
|
+
if id_in is not None:
|
648
|
+
where_stms["id_in"] = id_in
|
649
|
+
|
650
|
+
if question_id_in is not None:
|
651
|
+
where_stms["questionId_in"] = [x.hex() for x in question_id_in]
|
652
|
+
|
602
653
|
questions = self.realityeth_subgraph.Query.questions(where=where_stms)
|
603
654
|
fields = self._get_fields_for_reality_questions(questions)
|
604
655
|
result = self.sg.query_json(fields)
|
@@ -618,6 +669,17 @@ class OmenSubgraphHandler(metaclass=SingletonMeta):
|
|
618
669
|
items = self._parse_items_from_json(result)
|
619
670
|
return [RealityAnswer.model_validate(i) for i in items]
|
620
671
|
|
672
|
+
def get_responses(self, question_id: HexBytes) -> list[RealityResponse]:
|
673
|
+
response = self.realityeth_subgraph.Response
|
674
|
+
where_stms = [
|
675
|
+
response.question.questionId == question_id.hex(),
|
676
|
+
]
|
677
|
+
responses = self.realityeth_subgraph.Query.responses(where=where_stms)
|
678
|
+
fields = self._get_fields_for_responses(responses)
|
679
|
+
result = self.sg.query_json(fields)
|
680
|
+
items = self._parse_items_from_json(result)
|
681
|
+
return [RealityResponse.model_validate(i) for i in items]
|
682
|
+
|
621
683
|
def get_markets_from_all_user_positions(
|
622
684
|
self, user_positions: list[OmenUserPosition]
|
623
685
|
) -> list[OmenMarket]:
|
@@ -38,7 +38,7 @@ class Event(BaseModel):
|
|
38
38
|
|
39
39
|
|
40
40
|
class Event1(BaseModel):
|
41
|
-
startDate: datetime
|
41
|
+
startDate: datetime | None = None
|
42
42
|
slug: str
|
43
43
|
|
44
44
|
|
@@ -78,13 +78,13 @@ class Market(BaseModel):
|
|
78
78
|
conditionId: str
|
79
79
|
slug: str
|
80
80
|
twitterCardImage: t.Any | None = None
|
81
|
-
resolutionSource: str
|
81
|
+
resolutionSource: str | None = None
|
82
82
|
endDate: datetime
|
83
83
|
category: t.Any | None = None
|
84
84
|
ammType: t.Any | None = None
|
85
85
|
description: str
|
86
86
|
liquidity: str | None = None
|
87
|
-
startDate: datetime
|
87
|
+
startDate: datetime | None = None
|
88
88
|
createdAt: datetime
|
89
89
|
xAxisValue: t.Any | None = None
|
90
90
|
yAxisValue: t.Any | None = None
|
@@ -93,8 +93,8 @@ class Market(BaseModel):
|
|
93
93
|
lowerBound: t.Any | None = None
|
94
94
|
upperBound: t.Any | None = None
|
95
95
|
outcomes: list[str]
|
96
|
-
image: str
|
97
|
-
icon: str
|
96
|
+
image: str | None = None
|
97
|
+
icon: str | None = None
|
98
98
|
imageOptimized: t.Any | None = None
|
99
99
|
iconOptimized: t.Any | None = None
|
100
100
|
outcomePrices: list[USDC]
|
@@ -108,23 +108,23 @@ class Market(BaseModel):
|
|
108
108
|
marketMakerAddress: HexAddress
|
109
109
|
closedTime: datetime | None = None
|
110
110
|
wideFormat: bool | None = None
|
111
|
-
new: bool
|
111
|
+
new: bool | None = None
|
112
112
|
sentDiscord: t.Any | None = None
|
113
113
|
mailchimpTag: t.Any | None = None
|
114
|
-
featured: bool
|
115
|
-
submitted_by: str
|
114
|
+
featured: bool | None = None
|
115
|
+
submitted_by: str | None = None
|
116
116
|
subcategory: t.Any | None = None
|
117
117
|
categoryMailchimpTag: t.Any | None = None
|
118
|
-
archived: bool
|
119
|
-
resolvedBy: str
|
120
|
-
restricted: bool
|
121
|
-
groupItemTitle: str
|
122
|
-
groupItemThreshold: str
|
123
|
-
questionID: str
|
118
|
+
archived: bool | None = None
|
119
|
+
resolvedBy: str | None = None
|
120
|
+
restricted: bool | None = None
|
121
|
+
groupItemTitle: str | None = None
|
122
|
+
groupItemThreshold: str | None = None
|
123
|
+
questionID: str | None = None
|
124
124
|
umaEndDate: t.Any | None = None
|
125
|
-
enableOrderBook: bool
|
126
|
-
orderPriceMinTickSize: float
|
127
|
-
orderMinSize: int
|
125
|
+
enableOrderBook: bool | None = None
|
126
|
+
orderPriceMinTickSize: float | None = None
|
127
|
+
orderMinSize: int | None = None
|
128
128
|
umaResolutionStatus: t.Any | None = None
|
129
129
|
curationOrder: t.Any | None = None
|
130
130
|
volumeNum: USDC | None = None
|
@@ -134,9 +134,9 @@ class Market(BaseModel):
|
|
134
134
|
umaEndDateIso: datetime | None = None
|
135
135
|
commentsEnabled: bool | None = None
|
136
136
|
disqusThread: t.Any | None = None
|
137
|
-
gameStartTime:
|
137
|
+
gameStartTime: t.Any | None = None
|
138
138
|
secondsDelay: int | None = None
|
139
|
-
clobTokenIds: list[str]
|
139
|
+
clobTokenIds: list[str] | None = None
|
140
140
|
liquidityAmm: float | None = None
|
141
141
|
liquidityClob: float | None = None
|
142
142
|
makerBaseFee: int | None = None
|
@@ -144,27 +144,27 @@ class Market(BaseModel):
|
|
144
144
|
negRisk: t.Any | None = None
|
145
145
|
negRiskRequestID: t.Any | None = None
|
146
146
|
negRiskMarketID: t.Any | None = None
|
147
|
-
events: list[Event]
|
148
|
-
markets: list[Market1]
|
147
|
+
events: list[Event] | None = None
|
148
|
+
markets: list[Market1] | None = None
|
149
149
|
lower_bound_date: t.Any | None = None
|
150
150
|
upper_bound_date: t.Any | None = None
|
151
151
|
market_type: str | None = None
|
152
|
-
resolution_source: str
|
153
|
-
end_date: str
|
152
|
+
resolution_source: str | None = None
|
153
|
+
end_date: str | None = None
|
154
154
|
amm_type: t.Any | None = None
|
155
155
|
x_axis_value: t.Any | None = None
|
156
156
|
y_axis_value: t.Any | None = None
|
157
157
|
denomination_token: t.Any | None = None
|
158
|
-
resolved_by: str
|
158
|
+
resolved_by: str | None = None
|
159
159
|
upper_bound: t.Any | None = None
|
160
160
|
lower_bound: t.Any | None = None
|
161
|
-
created_at: str
|
161
|
+
created_at: str | None = None
|
162
162
|
updated_at: t.Any | None = None
|
163
163
|
closed_time: t.Any | None = None
|
164
164
|
wide_format: bool | None = None
|
165
165
|
volume_num: USDC | None = None
|
166
166
|
liquidity_num: USDC | None = None
|
167
|
-
image_raw: str
|
167
|
+
image_raw: str | None = None
|
168
168
|
resolutionData: ResolutionData
|
169
169
|
|
170
170
|
@field_validator("closedTime", mode="before")
|
@@ -234,19 +234,19 @@ class PolymarketFullMarket(BaseModel):
|
|
234
234
|
title: str
|
235
235
|
subtitle: t.Any | None = None
|
236
236
|
description: str
|
237
|
-
commentCount: int
|
238
|
-
resolutionSource: str
|
239
|
-
startDate: datetime
|
237
|
+
commentCount: int | None = None
|
238
|
+
resolutionSource: str | None = None
|
239
|
+
startDate: datetime | None = None
|
240
240
|
endDate: datetime
|
241
|
-
image: str
|
242
|
-
icon: str
|
241
|
+
image: str | None = None
|
242
|
+
icon: str | None = None
|
243
243
|
featuredImage: str | None = None
|
244
244
|
active: bool
|
245
245
|
closed: bool
|
246
|
-
archived: bool
|
247
|
-
new: bool
|
248
|
-
featured: bool
|
249
|
-
restricted: bool
|
246
|
+
archived: bool | None = None
|
247
|
+
new: bool | None = None
|
248
|
+
featured: bool | None = None
|
249
|
+
restricted: bool | None = None
|
250
250
|
liquidity: USDC | None = None
|
251
251
|
volume: USDC | None = None
|
252
252
|
volume24hr: USDC | None = None
|
@@ -257,7 +257,7 @@ class PolymarketFullMarket(BaseModel):
|
|
257
257
|
commentsEnabled: bool | None = None
|
258
258
|
disqusThread: t.Any | None = None
|
259
259
|
updatedAt: datetime
|
260
|
-
enableOrderBook: bool
|
260
|
+
enableOrderBook: bool | None = None
|
261
261
|
liquidityAmm: float | None = None
|
262
262
|
liquidityClob: float | None = None
|
263
263
|
imageOptimized: ImageOptimized | None = None
|
@@ -269,7 +269,7 @@ class PolymarketFullMarket(BaseModel):
|
|
269
269
|
markets: list[Market]
|
270
270
|
categories: list[Category] | None = None
|
271
271
|
series: t.Any | None = None
|
272
|
-
image_raw: str
|
272
|
+
image_raw: str | None = None
|
273
273
|
|
274
274
|
@property
|
275
275
|
def url(self) -> str:
|
@@ -298,6 +298,8 @@ class PolymarketFullMarket(BaseModel):
|
|
298
298
|
|
299
299
|
Warning: This is a very slow operation, as it requires fetching the website. Use it only when necessary.
|
300
300
|
"""
|
301
|
+
logger.info(f"Fetching full market from {url}")
|
302
|
+
|
301
303
|
# Fetch the website as a normal browser would.
|
302
304
|
headers = {
|
303
305
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
|
@@ -352,7 +354,8 @@ class State(BaseModel):
|
|
352
354
|
| dict[str, MarketBidsAndAsks]
|
353
355
|
| dict[str, PriceSide]
|
354
356
|
| None
|
355
|
-
|
357
|
+
# It's none if you go to the website and it says "Oops...we didn't forecast this".
|
358
|
+
)
|
356
359
|
dataUpdateCount: int
|
357
360
|
dataUpdatedAt: int
|
358
361
|
error: t.Any | None = None
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|