prediction-market-agent-tooling 0.65.5__py3-none-any.whl → 0.69.17.dev1149__py3-none-any.whl
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/abis/agentresultmapping.abi.json +192 -0
- prediction_market_agent_tooling/abis/erc1155.abi.json +352 -0
- prediction_market_agent_tooling/abis/processor.abi.json +16 -0
- prediction_market_agent_tooling/abis/swapr_quoter.abi.json +221 -0
- prediction_market_agent_tooling/abis/swapr_router.abi.json +634 -0
- prediction_market_agent_tooling/benchmark/benchmark.py +1 -1
- prediction_market_agent_tooling/benchmark/utils.py +13 -0
- prediction_market_agent_tooling/chains.py +1 -0
- prediction_market_agent_tooling/config.py +61 -2
- prediction_market_agent_tooling/data_download/langfuse_data_downloader.py +405 -0
- prediction_market_agent_tooling/deploy/agent.py +199 -67
- prediction_market_agent_tooling/deploy/agent_example.py +1 -1
- prediction_market_agent_tooling/deploy/betting_strategy.py +412 -68
- prediction_market_agent_tooling/deploy/constants.py +6 -0
- prediction_market_agent_tooling/gtypes.py +11 -1
- prediction_market_agent_tooling/jobs/jobs_models.py +2 -2
- prediction_market_agent_tooling/jobs/omen/omen_jobs.py +19 -20
- prediction_market_agent_tooling/loggers.py +9 -1
- prediction_market_agent_tooling/logprobs_parser.py +2 -1
- prediction_market_agent_tooling/markets/agent_market.py +106 -18
- prediction_market_agent_tooling/markets/blockchain_utils.py +37 -19
- prediction_market_agent_tooling/markets/data_models.py +120 -7
- prediction_market_agent_tooling/markets/manifold/data_models.py +5 -3
- prediction_market_agent_tooling/markets/manifold/manifold.py +21 -2
- prediction_market_agent_tooling/markets/manifold/utils.py +8 -2
- prediction_market_agent_tooling/markets/market_type.py +74 -0
- prediction_market_agent_tooling/markets/markets.py +7 -99
- prediction_market_agent_tooling/markets/metaculus/data_models.py +3 -3
- prediction_market_agent_tooling/markets/metaculus/metaculus.py +5 -8
- prediction_market_agent_tooling/markets/omen/cow_contracts.py +5 -1
- prediction_market_agent_tooling/markets/omen/data_models.py +63 -32
- prediction_market_agent_tooling/markets/omen/omen.py +112 -23
- prediction_market_agent_tooling/markets/omen/omen_constants.py +8 -0
- prediction_market_agent_tooling/markets/omen/omen_contracts.py +18 -203
- prediction_market_agent_tooling/markets/omen/omen_resolving.py +33 -13
- prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +23 -18
- prediction_market_agent_tooling/markets/polymarket/api.py +123 -100
- prediction_market_agent_tooling/markets/polymarket/clob_manager.py +156 -0
- prediction_market_agent_tooling/markets/polymarket/constants.py +15 -0
- prediction_market_agent_tooling/markets/polymarket/data_models.py +95 -19
- prediction_market_agent_tooling/markets/polymarket/polymarket.py +373 -29
- prediction_market_agent_tooling/markets/polymarket/polymarket_contracts.py +35 -0
- prediction_market_agent_tooling/markets/polymarket/polymarket_subgraph_handler.py +91 -0
- prediction_market_agent_tooling/markets/polymarket/utils.py +1 -22
- prediction_market_agent_tooling/markets/seer/data_models.py +111 -17
- prediction_market_agent_tooling/markets/seer/exceptions.py +2 -0
- prediction_market_agent_tooling/markets/seer/price_manager.py +165 -50
- prediction_market_agent_tooling/markets/seer/seer.py +393 -106
- prediction_market_agent_tooling/markets/seer/seer_api.py +28 -0
- prediction_market_agent_tooling/markets/seer/seer_contracts.py +115 -5
- prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +297 -66
- prediction_market_agent_tooling/markets/seer/subgraph_data_models.py +43 -8
- prediction_market_agent_tooling/markets/seer/swap_pool_handler.py +80 -0
- prediction_market_agent_tooling/tools/_generic_value.py +8 -2
- prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +271 -8
- prediction_market_agent_tooling/tools/betting_strategies/utils.py +6 -1
- prediction_market_agent_tooling/tools/caches/db_cache.py +219 -117
- prediction_market_agent_tooling/tools/caches/serializers.py +11 -2
- prediction_market_agent_tooling/tools/contract.py +480 -38
- prediction_market_agent_tooling/tools/contract_utils.py +61 -0
- prediction_market_agent_tooling/tools/cow/cow_order.py +218 -45
- prediction_market_agent_tooling/tools/cow/models.py +122 -0
- prediction_market_agent_tooling/tools/cow/semaphore.py +104 -0
- prediction_market_agent_tooling/tools/datetime_utc.py +14 -2
- prediction_market_agent_tooling/tools/db/db_manager.py +59 -0
- prediction_market_agent_tooling/tools/hexbytes_custom.py +4 -1
- prediction_market_agent_tooling/tools/httpx_cached_client.py +15 -6
- prediction_market_agent_tooling/tools/langfuse_client_utils.py +21 -8
- prediction_market_agent_tooling/tools/openai_utils.py +31 -0
- prediction_market_agent_tooling/tools/perplexity/perplexity_client.py +86 -0
- prediction_market_agent_tooling/tools/perplexity/perplexity_models.py +26 -0
- prediction_market_agent_tooling/tools/perplexity/perplexity_search.py +73 -0
- prediction_market_agent_tooling/tools/rephrase.py +71 -0
- prediction_market_agent_tooling/tools/singleton.py +11 -6
- prediction_market_agent_tooling/tools/streamlit_utils.py +188 -0
- prediction_market_agent_tooling/tools/tokens/auto_deposit.py +64 -0
- prediction_market_agent_tooling/tools/tokens/auto_withdraw.py +8 -0
- prediction_market_agent_tooling/tools/tokens/slippage.py +21 -0
- prediction_market_agent_tooling/tools/tokens/usd.py +5 -2
- prediction_market_agent_tooling/tools/utils.py +61 -3
- prediction_market_agent_tooling/tools/web3_utils.py +63 -9
- {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/METADATA +13 -9
- {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/RECORD +86 -64
- {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/WHEEL +1 -1
- prediction_market_agent_tooling/abis/omen_agentresultmapping.abi.json +0 -171
- prediction_market_agent_tooling/markets/polymarket/data_models_web.py +0 -420
- {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info}/entry_points.txt +0 -0
- {prediction_market_agent_tooling-0.65.5.dist-info → prediction_market_agent_tooling-0.69.17.dev1149.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import typing as t
|
|
2
|
+
from datetime import timedelta
|
|
2
3
|
|
|
3
4
|
from pydantic import BaseModel, ConfigDict, Field, computed_field, model_validator
|
|
4
5
|
from web3 import Web3
|
|
@@ -23,7 +24,12 @@ from prediction_market_agent_tooling.markets.data_models import (
|
|
|
23
24
|
Resolution,
|
|
24
25
|
ResolvedBet,
|
|
25
26
|
)
|
|
27
|
+
from prediction_market_agent_tooling.markets.omen.omen_constants import (
|
|
28
|
+
OMEN_FALSE_OUTCOME,
|
|
29
|
+
OMEN_TRUE_OUTCOME,
|
|
30
|
+
)
|
|
26
31
|
from prediction_market_agent_tooling.tools.contract import (
|
|
32
|
+
ConditionPreparationEvent,
|
|
27
33
|
ContractERC20OnGnosisChain,
|
|
28
34
|
init_collateral_token_contract,
|
|
29
35
|
to_gnosis_chain_contract,
|
|
@@ -37,15 +43,13 @@ from prediction_market_agent_tooling.tools.utils import (
|
|
|
37
43
|
utcnow,
|
|
38
44
|
)
|
|
39
45
|
|
|
40
|
-
OMEN_TRUE_OUTCOME = OutcomeStr("Yes")
|
|
41
|
-
OMEN_FALSE_OUTCOME = OutcomeStr("No")
|
|
42
46
|
OMEN_BINARY_MARKET_OUTCOMES: t.Sequence[OutcomeStr] = [
|
|
43
47
|
OMEN_TRUE_OUTCOME,
|
|
44
48
|
OMEN_FALSE_OUTCOME,
|
|
45
49
|
]
|
|
46
50
|
INVALID_ANSWER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
|
47
51
|
INVALID_ANSWER_HEX_BYTES = HexBytes(INVALID_ANSWER)
|
|
48
|
-
INVALID_ANSWER_STR = HexStr(INVALID_ANSWER_HEX_BYTES.
|
|
52
|
+
INVALID_ANSWER_STR = HexStr(INVALID_ANSWER_HEX_BYTES.to_0x_hex())
|
|
49
53
|
OMEN_BASE_URL = "https://aiomen.eth.limo"
|
|
50
54
|
PRESAGIO_BASE_URL = "https://presagio.pages.dev"
|
|
51
55
|
TEST_CATEGORY = "test" # This category is hidden on Presagio for testing purposes.
|
|
@@ -83,6 +87,7 @@ class Question(BaseModel):
|
|
|
83
87
|
templateId: int
|
|
84
88
|
outcomes: t.Sequence[OutcomeStr]
|
|
85
89
|
isPendingArbitration: bool
|
|
90
|
+
timeout: int # Finalization time in seconds
|
|
86
91
|
openingTimestamp: int
|
|
87
92
|
answerFinalizedTimestamp: t.Optional[DatetimeUTC] = None
|
|
88
93
|
currentAnswer: t.Optional[str] = None
|
|
@@ -96,6 +101,10 @@ class Question(BaseModel):
|
|
|
96
101
|
# Based on https://github.com/protofire/omen-exchange/blob/2cfdf6bfe37afa8b169731d51fea69d42321d66c/app/src/hooks/graph/useGraphMarketMakerData.tsx#L217.
|
|
97
102
|
return self.data
|
|
98
103
|
|
|
104
|
+
@property
|
|
105
|
+
def timeout_timedelta(self) -> timedelta:
|
|
106
|
+
return timedelta(seconds=self.timeout)
|
|
107
|
+
|
|
99
108
|
@property
|
|
100
109
|
def n_outcomes(self) -> int:
|
|
101
110
|
return len(self.outcomes)
|
|
@@ -253,6 +262,10 @@ class OmenMarket(BaseModel):
|
|
|
253
262
|
|
|
254
263
|
return self
|
|
255
264
|
|
|
265
|
+
@property
|
|
266
|
+
def creator_checksum(self) -> ChecksumAddress:
|
|
267
|
+
return Web3.to_checksum_address(self.creator)
|
|
268
|
+
|
|
256
269
|
@property
|
|
257
270
|
def openingTimestamp(self) -> int:
|
|
258
271
|
# This field is also available on this model itself, but for some reason it's typed to be optional,
|
|
@@ -468,6 +481,7 @@ class OmenMarket(BaseModel):
|
|
|
468
481
|
outcomes=model.question_event.parsed_question.outcomes,
|
|
469
482
|
isPendingArbitration=False, # Can not be, it's a fresh market.
|
|
470
483
|
openingTimestamp=model.question_event.opening_ts,
|
|
484
|
+
timeout=model.question_event.timeout,
|
|
471
485
|
answerFinalizedTimestamp=None, # It's a new one, can not be.
|
|
472
486
|
currentAnswer=None, # It's a new one, no answer yet.
|
|
473
487
|
),
|
|
@@ -592,14 +606,19 @@ class OmenBet(BaseModel):
|
|
|
592
606
|
)
|
|
593
607
|
|
|
594
608
|
return ResolvedBet(
|
|
595
|
-
id=self.transactionHash.
|
|
609
|
+
id=self.transactionHash.to_0x_hex(),
|
|
596
610
|
# Use the transaction hash instead of the bet id - both are valid, but we return the transaction hash from the trade functions, so be consistent here.
|
|
597
611
|
amount=self.collateral_amount_token,
|
|
598
612
|
outcome=self.fpmm.outcomes[self.outcomeIndex],
|
|
599
613
|
created_time=self.creation_datetime,
|
|
600
614
|
market_question=self.title,
|
|
601
615
|
market_id=self.fpmm.id,
|
|
602
|
-
market_outcome=self.fpmm.outcomes[
|
|
616
|
+
market_outcome=self.fpmm.outcomes[
|
|
617
|
+
check_not_none(
|
|
618
|
+
self.fpmm.answer_index,
|
|
619
|
+
"Should not be None if `is_resolved_with_valid_answer`.",
|
|
620
|
+
)
|
|
621
|
+
],
|
|
603
622
|
resolved_time=check_not_none(self.fpmm.finalized_datetime),
|
|
604
623
|
profit=self.get_profit(),
|
|
605
624
|
)
|
|
@@ -788,13 +807,6 @@ class OmenFixedProductMarketMakerCreationEvent(BaseModel):
|
|
|
788
807
|
return Web3.to_checksum_address(self.collateralToken)
|
|
789
808
|
|
|
790
809
|
|
|
791
|
-
class ConditionPreparationEvent(BaseModel):
|
|
792
|
-
conditionId: HexBytes
|
|
793
|
-
oracle: HexAddress
|
|
794
|
-
questionId: HexBytes
|
|
795
|
-
outcomeSlotCount: int
|
|
796
|
-
|
|
797
|
-
|
|
798
810
|
class FPMMFundingAddedEvent(BaseModel):
|
|
799
811
|
funder: HexAddress
|
|
800
812
|
amountsAdded: list[Wei]
|
|
@@ -826,18 +838,44 @@ class CreatedMarket(BaseModel):
|
|
|
826
838
|
|
|
827
839
|
class ContractPrediction(BaseModel):
|
|
828
840
|
model_config = ConfigDict(populate_by_name=True)
|
|
841
|
+
|
|
842
|
+
market: str | None = Field(
|
|
843
|
+
None,
|
|
844
|
+
alias="marketAddress",
|
|
845
|
+
description="Market's address. Will be None on older records.",
|
|
846
|
+
)
|
|
829
847
|
publisher: str = Field(..., alias="publisherAddress")
|
|
830
848
|
ipfs_hash: HexBytes = Field(..., alias="ipfsHash")
|
|
831
849
|
tx_hashes: list[HexBytes] = Field(..., alias="txHashes")
|
|
832
|
-
|
|
850
|
+
outcomes: list[OutcomeStr] = Field(...)
|
|
851
|
+
estimated_probabilities_bps: list[int] = Field(
|
|
852
|
+
..., alias="estimatedProbabilitiesBps"
|
|
853
|
+
)
|
|
833
854
|
|
|
834
|
-
@
|
|
835
|
-
|
|
836
|
-
|
|
855
|
+
@model_validator(mode="before")
|
|
856
|
+
@classmethod
|
|
857
|
+
def handle_legacy_estimated_probability_bps(
|
|
858
|
+
cls, values: dict[str, t.Any]
|
|
859
|
+
) -> dict[str, t.Any]:
|
|
860
|
+
# If 'estimatedProbabilityBps' is present and 'outcomes'/'estimatedProbabilitiesBps' are not,
|
|
861
|
+
# convert to the new format using "Yes" and "No" outcomes.
|
|
862
|
+
# This allows for backward compatibility with old contract events.
|
|
863
|
+
if (
|
|
864
|
+
"estimatedProbabilityBps" in values
|
|
865
|
+
and "outcomes" not in values
|
|
866
|
+
and "estimatedProbabilitiesBps" not in values
|
|
867
|
+
):
|
|
868
|
+
prob_bps = values["estimatedProbabilityBps"]
|
|
869
|
+
values["outcomes"] = [
|
|
870
|
+
OMEN_TRUE_OUTCOME,
|
|
871
|
+
OMEN_FALSE_OUTCOME,
|
|
872
|
+
]
|
|
873
|
+
values["estimatedProbabilitiesBps"] = [prob_bps, BPS_CONSTANT - prob_bps]
|
|
874
|
+
return values
|
|
837
875
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
return self.
|
|
876
|
+
def estimated_probability_of_outcome(self, outcome: OutcomeStr) -> Probability:
|
|
877
|
+
index = self.outcomes.index(outcome)
|
|
878
|
+
return Probability(self.estimated_probabilities_bps[index] / BPS_CONSTANT)
|
|
841
879
|
|
|
842
880
|
@computed_field # type: ignore[prop-decorator] # Mypy issue: https://github.com/python/mypy/issues/14461
|
|
843
881
|
@property
|
|
@@ -847,10 +885,12 @@ class ContractPrediction(BaseModel):
|
|
|
847
885
|
@staticmethod
|
|
848
886
|
def from_tuple(values: tuple[t.Any, ...]) -> "ContractPrediction":
|
|
849
887
|
return ContractPrediction(
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
888
|
+
market=values[0],
|
|
889
|
+
publisher=values[1],
|
|
890
|
+
ipfs_hash=values[2],
|
|
891
|
+
tx_hashes=values[3],
|
|
892
|
+
outcomes=values[4],
|
|
893
|
+
estimated_probabilities_bps=values[5],
|
|
854
894
|
)
|
|
855
895
|
|
|
856
896
|
|
|
@@ -860,12 +900,3 @@ class IPFSAgentResult(BaseModel):
|
|
|
860
900
|
model_config = ConfigDict(
|
|
861
901
|
extra="forbid",
|
|
862
902
|
)
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
class PayoutRedemptionEvent(BaseModel):
|
|
866
|
-
redeemer: HexAddress
|
|
867
|
-
collateralToken: HexAddress
|
|
868
|
-
parentCollectionId: HexBytes
|
|
869
|
-
conditionId: HexBytes
|
|
870
|
-
indexSets: list[int]
|
|
871
|
-
payout: Wei
|
|
@@ -3,8 +3,10 @@ from collections import defaultdict
|
|
|
3
3
|
from datetime import timedelta
|
|
4
4
|
|
|
5
5
|
import tenacity
|
|
6
|
+
from pydantic import BaseModel
|
|
6
7
|
from tqdm import tqdm
|
|
7
8
|
from web3 import Web3
|
|
9
|
+
from web3.constants import HASH_ZERO
|
|
8
10
|
|
|
9
11
|
from prediction_market_agent_tooling.config import APIKeys
|
|
10
12
|
from prediction_market_agent_tooling.gtypes import (
|
|
@@ -23,10 +25,11 @@ from prediction_market_agent_tooling.gtypes import (
|
|
|
23
25
|
from prediction_market_agent_tooling.loggers import logger
|
|
24
26
|
from prediction_market_agent_tooling.markets.agent_market import (
|
|
25
27
|
AgentMarket,
|
|
28
|
+
ConditionalFilterType,
|
|
26
29
|
FilterBy,
|
|
27
30
|
MarketFees,
|
|
28
31
|
ProcessedMarket,
|
|
29
|
-
|
|
32
|
+
QuestionType,
|
|
30
33
|
SortBy,
|
|
31
34
|
)
|
|
32
35
|
from prediction_market_agent_tooling.markets.blockchain_utils import store_trades
|
|
@@ -40,7 +43,6 @@ from prediction_market_agent_tooling.markets.omen.data_models import (
|
|
|
40
43
|
OMEN_TRUE_OUTCOME,
|
|
41
44
|
PRESAGIO_BASE_URL,
|
|
42
45
|
Condition,
|
|
43
|
-
ConditionPreparationEvent,
|
|
44
46
|
CreatedMarket,
|
|
45
47
|
OmenBet,
|
|
46
48
|
OmenMarket,
|
|
@@ -50,19 +52,20 @@ from prediction_market_agent_tooling.markets.omen.omen_contracts import (
|
|
|
50
52
|
OMEN_DEFAULT_MARKET_FEE_PERC,
|
|
51
53
|
REALITY_DEFAULT_FINALIZATION_TIMEOUT,
|
|
52
54
|
Arbitrator,
|
|
55
|
+
OmenAgentResultMappingContract,
|
|
53
56
|
OmenConditionalTokenContract,
|
|
54
57
|
OmenFixedProductMarketMakerContract,
|
|
55
58
|
OmenFixedProductMarketMakerFactoryContract,
|
|
56
59
|
OmenOracleContract,
|
|
57
60
|
OmenRealitioContract,
|
|
58
61
|
WrappedxDaiContract,
|
|
59
|
-
build_parent_collection_id,
|
|
60
62
|
)
|
|
61
63
|
from prediction_market_agent_tooling.markets.omen.omen_subgraph_handler import (
|
|
62
64
|
OmenSubgraphHandler,
|
|
63
65
|
)
|
|
64
66
|
from prediction_market_agent_tooling.tools.balances import get_balances
|
|
65
67
|
from prediction_market_agent_tooling.tools.contract import (
|
|
68
|
+
ConditionPreparationEvent,
|
|
66
69
|
init_collateral_token_contract,
|
|
67
70
|
to_gnosis_chain_contract,
|
|
68
71
|
)
|
|
@@ -84,10 +87,10 @@ from prediction_market_agent_tooling.tools.utils import (
|
|
|
84
87
|
DatetimeUTC,
|
|
85
88
|
calculate_sell_amount_in_collateral,
|
|
86
89
|
check_not_none,
|
|
90
|
+
utcnow,
|
|
87
91
|
)
|
|
88
92
|
from prediction_market_agent_tooling.tools.web3_utils import get_receipt_block_timestamp
|
|
89
93
|
|
|
90
|
-
OMEN_DEFAULT_REALITIO_BOND_VALUE = xDai(0.01)
|
|
91
94
|
# Too low value would work with the Omen contract, but causes CoW orders (when buying the specific market's tokens) to fail.
|
|
92
95
|
OMEN_TINY_BET_AMOUNT = USD(0.01)
|
|
93
96
|
|
|
@@ -102,6 +105,7 @@ class OmenAgentMarket(AgentMarket):
|
|
|
102
105
|
|
|
103
106
|
collateral_token_contract_address_checksummed: ChecksumAddress
|
|
104
107
|
market_maker_contract_address_checksummed: ChecksumAddress
|
|
108
|
+
outcome_token_pool: dict[OutcomeStr, OutcomeToken]
|
|
105
109
|
condition: Condition
|
|
106
110
|
finalized_time: DatetimeUTC | None
|
|
107
111
|
created_time: DatetimeUTC
|
|
@@ -157,6 +161,14 @@ class OmenAgentMarket(AgentMarket):
|
|
|
157
161
|
def get_usd_in_token(self, x: USD) -> CollateralToken:
|
|
158
162
|
return get_usd_in_token(x, self.collateral_token_contract_address_checksummed)
|
|
159
163
|
|
|
164
|
+
def have_bet_on_market_since(self, keys: APIKeys, since: timedelta) -> bool:
|
|
165
|
+
start_time = utcnow() - since
|
|
166
|
+
prev_bets = self.get_bets_made_since(
|
|
167
|
+
better_address=keys.bet_from_address, start_time=start_time
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
return self.id in [b.market_id for b in prev_bets]
|
|
171
|
+
|
|
160
172
|
def liquidate_existing_positions(
|
|
161
173
|
self,
|
|
162
174
|
bet_outcome: OutcomeStr,
|
|
@@ -368,8 +380,11 @@ class OmenAgentMarket(AgentMarket):
|
|
|
368
380
|
filter_by: FilterBy = FilterBy.OPEN,
|
|
369
381
|
created_after: t.Optional[DatetimeUTC] = None,
|
|
370
382
|
excluded_questions: set[str] | None = None,
|
|
371
|
-
|
|
383
|
+
question_type: QuestionType = QuestionType.ALL,
|
|
384
|
+
conditional_filter_type: ConditionalFilterType = ConditionalFilterType.ONLY_NOT_CONDITIONAL,
|
|
372
385
|
) -> t.Sequence["OmenAgentMarket"]:
|
|
386
|
+
fetch_categorical_markets = question_type == QuestionType.CATEGORICAL
|
|
387
|
+
|
|
373
388
|
return [
|
|
374
389
|
OmenAgentMarket.from_data_model(m)
|
|
375
390
|
for m in OmenSubgraphHandler().get_omen_markets_simple(
|
|
@@ -394,6 +409,26 @@ class OmenAgentMarket(AgentMarket):
|
|
|
394
409
|
def redeem_winnings(api_keys: APIKeys) -> None:
|
|
395
410
|
redeem_from_all_user_positions(api_keys)
|
|
396
411
|
|
|
412
|
+
def ensure_min_native_balance(
|
|
413
|
+
self,
|
|
414
|
+
min_required_balance: xDai,
|
|
415
|
+
multiplier: float = 3.0,
|
|
416
|
+
) -> None:
|
|
417
|
+
"""
|
|
418
|
+
Ensure the EOA has at least the minimum required native token balance.
|
|
419
|
+
If not, transfer wrapped native tokens from the betting address and unwrap them.
|
|
420
|
+
|
|
421
|
+
Args:
|
|
422
|
+
min_required_balance: Minimum required native token balance to maintain
|
|
423
|
+
multiplier: Multiplier to apply to the required balance to keep as a buffer
|
|
424
|
+
"""
|
|
425
|
+
|
|
426
|
+
send_keeping_token_to_eoa_xdai(
|
|
427
|
+
api_keys=APIKeys(),
|
|
428
|
+
min_required_balance=min_required_balance,
|
|
429
|
+
multiplier=multiplier,
|
|
430
|
+
)
|
|
431
|
+
|
|
397
432
|
@staticmethod
|
|
398
433
|
def get_trade_balance(api_keys: APIKeys, web3: Web3 | None = None) -> USD:
|
|
399
434
|
native_usd = get_xdai_in_usd(
|
|
@@ -421,16 +456,19 @@ class OmenAgentMarket(AgentMarket):
|
|
|
421
456
|
|
|
422
457
|
def store_trades(
|
|
423
458
|
self,
|
|
424
|
-
traded_market:
|
|
459
|
+
traded_market: ProcessedMarket | None,
|
|
425
460
|
keys: APIKeys,
|
|
426
461
|
agent_name: str,
|
|
427
462
|
web3: Web3 | None = None,
|
|
428
463
|
) -> None:
|
|
429
464
|
return store_trades(
|
|
430
|
-
|
|
465
|
+
contract=OmenAgentResultMappingContract(),
|
|
466
|
+
market_id=Web3.to_checksum_address(self.id),
|
|
467
|
+
outcomes=self.outcomes,
|
|
431
468
|
traded_market=traded_market,
|
|
432
469
|
keys=keys,
|
|
433
470
|
agent_name=agent_name,
|
|
471
|
+
web3=web3,
|
|
434
472
|
)
|
|
435
473
|
|
|
436
474
|
@staticmethod
|
|
@@ -607,11 +645,10 @@ class OmenAgentMarket(AgentMarket):
|
|
|
607
645
|
Note: this is only valid if the market instance's token pool is
|
|
608
646
|
up-to-date with the smart contract.
|
|
609
647
|
"""
|
|
610
|
-
outcome_token_pool = check_not_none(self.outcome_token_pool)
|
|
611
648
|
amount = get_buy_outcome_token_amount(
|
|
612
649
|
investment_amount=self.get_in_token(bet_amount),
|
|
613
650
|
outcome_index=self.get_outcome_index(outcome),
|
|
614
|
-
pool_balances=[outcome_token_pool[x] for x in self.outcomes],
|
|
651
|
+
pool_balances=[self.outcome_token_pool[x] for x in self.outcomes],
|
|
615
652
|
fees=self.fees,
|
|
616
653
|
)
|
|
617
654
|
return amount
|
|
@@ -634,10 +671,6 @@ class OmenAgentMarket(AgentMarket):
|
|
|
634
671
|
def get_user_balance(user_id: str) -> float:
|
|
635
672
|
return float(get_balances(Web3.to_checksum_address(user_id)).total)
|
|
636
673
|
|
|
637
|
-
@staticmethod
|
|
638
|
-
def get_user_id(api_keys: APIKeys) -> str:
|
|
639
|
-
return api_keys.bet_from_address
|
|
640
|
-
|
|
641
674
|
def get_most_recent_trade_datetime(self, user_id: str) -> DatetimeUTC | None:
|
|
642
675
|
sgh = OmenSubgraphHandler()
|
|
643
676
|
trades = sgh.get_trades(
|
|
@@ -670,6 +703,26 @@ def omen_buy_outcome_tx(
|
|
|
670
703
|
auto_deposit: bool,
|
|
671
704
|
web3: Web3 | None = None,
|
|
672
705
|
slippage: float = 0.01,
|
|
706
|
+
) -> str:
|
|
707
|
+
return omen_buy_outcome_tx_no_retry(
|
|
708
|
+
api_keys=api_keys,
|
|
709
|
+
amount=amount,
|
|
710
|
+
market=market,
|
|
711
|
+
outcome=outcome,
|
|
712
|
+
auto_deposit=auto_deposit,
|
|
713
|
+
web3=web3,
|
|
714
|
+
slippage=slippage,
|
|
715
|
+
)
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
def omen_buy_outcome_tx_no_retry(
|
|
719
|
+
api_keys: APIKeys,
|
|
720
|
+
amount: USD | CollateralToken,
|
|
721
|
+
market: OmenAgentMarket,
|
|
722
|
+
outcome: OutcomeStr,
|
|
723
|
+
auto_deposit: bool,
|
|
724
|
+
web3: Web3 | None = None,
|
|
725
|
+
slippage: float = 0.01,
|
|
673
726
|
) -> str:
|
|
674
727
|
"""
|
|
675
728
|
Bets the given amount for the given outcome in the given market.
|
|
@@ -715,7 +768,7 @@ def omen_buy_outcome_tx(
|
|
|
715
768
|
web3=web3,
|
|
716
769
|
)
|
|
717
770
|
|
|
718
|
-
return tx_receipt["transactionHash"].
|
|
771
|
+
return tx_receipt["transactionHash"].to_0x_hex()
|
|
719
772
|
|
|
720
773
|
|
|
721
774
|
def binary_omen_buy_outcome_tx(
|
|
@@ -809,7 +862,7 @@ def omen_sell_outcome_tx(
|
|
|
809
862
|
web3=web3,
|
|
810
863
|
)
|
|
811
864
|
|
|
812
|
-
return tx_receipt["transactionHash"].
|
|
865
|
+
return tx_receipt["transactionHash"].to_0x_hex()
|
|
813
866
|
|
|
814
867
|
|
|
815
868
|
def binary_omen_sell_outcome_tx(
|
|
@@ -1057,11 +1110,11 @@ def get_conditional_tokens_balance_for_market(
|
|
|
1057
1110
|
"""
|
|
1058
1111
|
balance_per_index_set: dict[int, OutcomeWei] = {}
|
|
1059
1112
|
conditional_token_contract = OmenConditionalTokenContract()
|
|
1060
|
-
parent_collection_id =
|
|
1113
|
+
parent_collection_id = HASH_ZERO
|
|
1061
1114
|
|
|
1062
1115
|
for index_set in market.condition.index_sets:
|
|
1063
1116
|
collection_id = conditional_token_contract.getCollectionId(
|
|
1064
|
-
parent_collection_id, market.condition.id, index_set, web3=web3
|
|
1117
|
+
HexBytes(parent_collection_id), market.condition.id, index_set, web3=web3
|
|
1065
1118
|
)
|
|
1066
1119
|
# Note that collection_id is returned as bytes, which is accepted by the contract calls downstream.
|
|
1067
1120
|
position_id: int = conditional_token_contract.getPositionId(
|
|
@@ -1305,20 +1358,34 @@ def send_keeping_token_to_eoa_xdai(
|
|
|
1305
1358
|
)
|
|
1306
1359
|
|
|
1307
1360
|
|
|
1308
|
-
|
|
1361
|
+
class BuyOutcomeResult(BaseModel):
|
|
1362
|
+
outcome_tokens_received: OutcomeToken
|
|
1363
|
+
new_pool_balances: list[OutcomeToken]
|
|
1364
|
+
|
|
1365
|
+
|
|
1366
|
+
def calculate_buy_outcome_token(
|
|
1309
1367
|
investment_amount: CollateralToken,
|
|
1310
1368
|
outcome_index: int,
|
|
1311
1369
|
pool_balances: list[OutcomeToken],
|
|
1312
1370
|
fees: MarketFees,
|
|
1313
|
-
) ->
|
|
1371
|
+
) -> BuyOutcomeResult:
|
|
1314
1372
|
"""
|
|
1315
1373
|
Calculates the amount of outcome tokens received for a given investment
|
|
1374
|
+
and returns the new pool balances after the purchase.
|
|
1316
1375
|
|
|
1317
1376
|
Taken from https://github.com/gnosis/conditional-tokens-market-makers/blob/6814c0247c745680bb13298d4f0dd7f5b574d0db/contracts/FixedProductMarketMaker.sol#L264
|
|
1318
1377
|
"""
|
|
1319
1378
|
if outcome_index >= len(pool_balances):
|
|
1320
1379
|
raise ValueError("invalid outcome index")
|
|
1321
1380
|
|
|
1381
|
+
new_pool_balances = pool_balances.copy()
|
|
1382
|
+
|
|
1383
|
+
if investment_amount == 0:
|
|
1384
|
+
return BuyOutcomeResult(
|
|
1385
|
+
outcome_tokens_received=OutcomeToken(0),
|
|
1386
|
+
new_pool_balances=new_pool_balances,
|
|
1387
|
+
)
|
|
1388
|
+
|
|
1322
1389
|
investment_amount_minus_fees = fees.get_after_fees(investment_amount)
|
|
1323
1390
|
investment_amount_minus_fees_as_ot = OutcomeToken(
|
|
1324
1391
|
investment_amount_minus_fees.value
|
|
@@ -1330,17 +1397,39 @@ def get_buy_outcome_token_amount(
|
|
|
1330
1397
|
# Calculate the ending balance considering all other outcomes
|
|
1331
1398
|
for i, pool_balance in enumerate(pool_balances):
|
|
1332
1399
|
if i != outcome_index:
|
|
1333
|
-
|
|
1400
|
+
new_pool_balances[i] = pool_balance + investment_amount_minus_fees_as_ot
|
|
1334
1401
|
ending_outcome_balance = OutcomeToken(
|
|
1335
|
-
(ending_outcome_balance * pool_balance /
|
|
1402
|
+
(ending_outcome_balance * pool_balance / new_pool_balances[i])
|
|
1336
1403
|
)
|
|
1337
1404
|
|
|
1405
|
+
# Update the bought outcome's pool balance
|
|
1406
|
+
new_pool_balances[outcome_index] = ending_outcome_balance
|
|
1407
|
+
|
|
1338
1408
|
if ending_outcome_balance <= 0:
|
|
1339
1409
|
raise ValueError("must have non-zero balances")
|
|
1340
1410
|
|
|
1341
|
-
|
|
1411
|
+
outcome_tokens_received = (
|
|
1342
1412
|
buy_token_pool_balance
|
|
1343
1413
|
+ investment_amount_minus_fees_as_ot
|
|
1344
1414
|
- ending_outcome_balance
|
|
1345
1415
|
)
|
|
1346
|
-
|
|
1416
|
+
|
|
1417
|
+
return BuyOutcomeResult(
|
|
1418
|
+
outcome_tokens_received=outcome_tokens_received,
|
|
1419
|
+
new_pool_balances=new_pool_balances,
|
|
1420
|
+
)
|
|
1421
|
+
|
|
1422
|
+
|
|
1423
|
+
def get_buy_outcome_token_amount(
|
|
1424
|
+
investment_amount: CollateralToken,
|
|
1425
|
+
outcome_index: int,
|
|
1426
|
+
pool_balances: list[OutcomeToken],
|
|
1427
|
+
fees: MarketFees,
|
|
1428
|
+
) -> OutcomeToken:
|
|
1429
|
+
result = calculate_buy_outcome_token(
|
|
1430
|
+
investment_amount=investment_amount,
|
|
1431
|
+
outcome_index=outcome_index,
|
|
1432
|
+
pool_balances=pool_balances,
|
|
1433
|
+
fees=fees,
|
|
1434
|
+
)
|
|
1435
|
+
return result.outcome_tokens_received
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
from web3 import Web3
|
|
2
2
|
|
|
3
|
+
from prediction_market_agent_tooling.gtypes import OutcomeStr
|
|
4
|
+
|
|
5
|
+
OMEN_TRUE_OUTCOME = OutcomeStr("Yes")
|
|
6
|
+
OMEN_FALSE_OUTCOME = OutcomeStr("No")
|
|
7
|
+
|
|
3
8
|
WRAPPED_XDAI_CONTRACT_ADDRESS = Web3.to_checksum_address(
|
|
4
9
|
"0xe91d153e0b41518a2ce8dd3d7944fa863463a97d"
|
|
5
10
|
)
|
|
6
11
|
SDAI_CONTRACT_ADDRESS = Web3.to_checksum_address(
|
|
7
12
|
"0xaf204776c7245bF4147c2612BF6e5972Ee483701"
|
|
8
13
|
)
|
|
14
|
+
METRI_SUPER_GROUP_CONTRACT_ADDRESS = Web3.to_checksum_address(
|
|
15
|
+
"0x7147A7405fCFe5CFa30c6d5363f9f357a317d082"
|
|
16
|
+
)
|