prediction-market-agent-tooling 0.48.18__py3-none-any.whl → 0.49.1__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/debuggingcontract.abi.json +29 -0
- prediction_market_agent_tooling/abis/omen_agentresultmapping.abi.json +171 -0
- prediction_market_agent_tooling/benchmark/benchmark.py +0 -93
- prediction_market_agent_tooling/config.py +16 -0
- prediction_market_agent_tooling/deploy/agent.py +86 -13
- prediction_market_agent_tooling/deploy/betting_strategy.py +5 -35
- prediction_market_agent_tooling/jobs/omen/omen_jobs.py +2 -1
- prediction_market_agent_tooling/markets/agent_market.py +14 -6
- prediction_market_agent_tooling/markets/data_models.py +14 -0
- prediction_market_agent_tooling/markets/manifold/api.py +3 -1
- prediction_market_agent_tooling/markets/manifold/manifold.py +7 -2
- prediction_market_agent_tooling/markets/metaculus/metaculus.py +6 -1
- prediction_market_agent_tooling/markets/omen/data_models.py +247 -6
- prediction_market_agent_tooling/markets/omen/omen.py +77 -43
- prediction_market_agent_tooling/markets/omen/omen_contracts.py +179 -33
- prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +35 -0
- prediction_market_agent_tooling/markets/polymarket/polymarket.py +1 -1
- prediction_market_agent_tooling/monitor/markets/polymarket.py +4 -0
- prediction_market_agent_tooling/monitor/monitor.py +3 -3
- prediction_market_agent_tooling/monitor/monitor_app.py +2 -2
- prediction_market_agent_tooling/tools/contract.py +50 -1
- prediction_market_agent_tooling/tools/ipfs/ipfs_handler.py +33 -0
- prediction_market_agent_tooling/tools/langfuse_client_utils.py +27 -12
- prediction_market_agent_tooling/tools/utils.py +28 -4
- prediction_market_agent_tooling/tools/web3_utils.py +7 -0
- {prediction_market_agent_tooling-0.48.18.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/METADATA +2 -1
- {prediction_market_agent_tooling-0.48.18.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/RECORD +30 -27
- {prediction_market_agent_tooling-0.48.18.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.48.18.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/WHEEL +0 -0
- {prediction_market_agent_tooling-0.48.18.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/entry_points.txt +0 -0
@@ -18,8 +18,8 @@ from prediction_market_agent_tooling.markets.data_models import (
|
|
18
18
|
TokenAmount,
|
19
19
|
)
|
20
20
|
from prediction_market_agent_tooling.tools.utils import (
|
21
|
-
add_utc_timezone_validator,
|
22
21
|
check_not_none,
|
22
|
+
convert_to_utc_datetime,
|
23
23
|
should_not_happen,
|
24
24
|
utcnow,
|
25
25
|
)
|
@@ -61,10 +61,10 @@ class AgentMarket(BaseModel):
|
|
61
61
|
volume: float | None # Should be in currency of `currency` above.
|
62
62
|
|
63
63
|
_add_timezone_validator_created_time = field_validator("created_time")(
|
64
|
-
|
64
|
+
convert_to_utc_datetime
|
65
65
|
)
|
66
66
|
_add_timezone_validator_close_time = field_validator("close_time")(
|
67
|
-
|
67
|
+
convert_to_utc_datetime
|
68
68
|
)
|
69
69
|
|
70
70
|
@field_validator("outcome_token_pool")
|
@@ -166,13 +166,13 @@ class AgentMarket(BaseModel):
|
|
166
166
|
def liquidate_existing_positions(self, outcome: bool) -> None:
|
167
167
|
raise NotImplementedError("Subclasses must implement this method")
|
168
168
|
|
169
|
-
def place_bet(self, outcome: bool, amount: BetAmount) ->
|
169
|
+
def place_bet(self, outcome: bool, amount: BetAmount) -> str:
|
170
170
|
raise NotImplementedError("Subclasses must implement this method")
|
171
171
|
|
172
|
-
def buy_tokens(self, outcome: bool, amount: TokenAmount) ->
|
172
|
+
def buy_tokens(self, outcome: bool, amount: TokenAmount) -> str:
|
173
173
|
return self.place_bet(outcome=outcome, amount=amount)
|
174
174
|
|
175
|
-
def sell_tokens(self, outcome: bool, amount: TokenAmount) ->
|
175
|
+
def sell_tokens(self, outcome: bool, amount: TokenAmount) -> str:
|
176
176
|
raise NotImplementedError("Subclasses must implement this method")
|
177
177
|
|
178
178
|
@staticmethod
|
@@ -281,3 +281,11 @@ class AgentMarket(BaseModel):
|
|
281
281
|
raise ValueError("Outcome token pool is not available.")
|
282
282
|
|
283
283
|
return self.outcome_token_pool[outcome]
|
284
|
+
|
285
|
+
@staticmethod
|
286
|
+
def get_user_balance(user_id: str) -> float:
|
287
|
+
raise NotImplementedError("Subclasses must implement this method")
|
288
|
+
|
289
|
+
@staticmethod
|
290
|
+
def get_user_id(api_keys: APIKeys) -> str:
|
291
|
+
raise NotImplementedError("Subclasses must implement this method")
|
@@ -37,6 +37,7 @@ ProfitAmount: TypeAlias = TokenAmount
|
|
37
37
|
|
38
38
|
|
39
39
|
class Bet(BaseModel):
|
40
|
+
id: str
|
40
41
|
amount: BetAmount
|
41
42
|
outcome: bool
|
42
43
|
created_time: datetime
|
@@ -126,3 +127,16 @@ class Trade(BaseModel):
|
|
126
127
|
trade_type: TradeType
|
127
128
|
outcome: bool
|
128
129
|
amount: TokenAmount
|
130
|
+
|
131
|
+
|
132
|
+
class PlacedTrade(Trade):
|
133
|
+
id: str | None = None
|
134
|
+
|
135
|
+
@staticmethod
|
136
|
+
def from_trade(trade: Trade, id: str) -> "PlacedTrade":
|
137
|
+
return PlacedTrade(
|
138
|
+
trade_type=trade.trade_type,
|
139
|
+
outcome=trade.outcome,
|
140
|
+
amount=trade.amount,
|
141
|
+
id=id,
|
142
|
+
)
|
@@ -110,7 +110,7 @@ def get_one_manifold_binary_market() -> ManifoldMarket:
|
|
110
110
|
)
|
111
111
|
def place_bet(
|
112
112
|
amount: Mana, market_id: str, outcome: bool, manifold_api_key: SecretStr
|
113
|
-
) ->
|
113
|
+
) -> ManifoldBet:
|
114
114
|
outcome_str = "YES" if outcome else "NO"
|
115
115
|
url = f"{MANIFOLD_API_BASE_URL}/v0/bet"
|
116
116
|
params = {
|
@@ -131,6 +131,7 @@ def place_bet(
|
|
131
131
|
raise RuntimeError(
|
132
132
|
f"Placing bet failed: {response.status_code} {response.reason} {response.text}"
|
133
133
|
)
|
134
|
+
return ManifoldBet.model_validate(data)
|
134
135
|
else:
|
135
136
|
raise Exception(
|
136
137
|
f"Placing bet failed: {response.status_code} {response.reason} {response.text}"
|
@@ -209,6 +210,7 @@ def manifold_to_generic_resolved_bet(
|
|
209
210
|
|
210
211
|
market_outcome = market.get_resolved_boolean_outcome()
|
211
212
|
return ResolvedBet(
|
213
|
+
id=bet.id,
|
212
214
|
amount=BetAmount(amount=bet.amount, currency=Currency.Mana),
|
213
215
|
outcome=bet.get_resolved_boolean_outcome(),
|
214
216
|
created_time=bet.createdTime,
|
@@ -49,15 +49,16 @@ class ManifoldAgentMarket(AgentMarket):
|
|
49
49
|
# Manifold lowest bet is 1 Mana, so we need to ceil the result.
|
50
50
|
return mana_type(ceil(minimum_bet_to_win(answer, amount_to_win, self)))
|
51
51
|
|
52
|
-
def place_bet(self, outcome: bool, amount: BetAmount) ->
|
52
|
+
def place_bet(self, outcome: bool, amount: BetAmount) -> str:
|
53
53
|
if amount.currency != self.currency:
|
54
54
|
raise ValueError(f"Manifold bets are made in Mana. Got {amount.currency}.")
|
55
|
-
place_bet(
|
55
|
+
bet = place_bet(
|
56
56
|
amount=Mana(amount.amount),
|
57
57
|
market_id=self.id,
|
58
58
|
outcome=outcome,
|
59
59
|
manifold_api_key=APIKeys().manifold_api_key,
|
60
60
|
)
|
61
|
+
return bet.id
|
61
62
|
|
62
63
|
@staticmethod
|
63
64
|
def from_data_model(model: FullManifoldMarket) -> "ManifoldAgentMarket":
|
@@ -119,3 +120,7 @@ class ManifoldAgentMarket(AgentMarket):
|
|
119
120
|
@classmethod
|
120
121
|
def get_user_url(cls, keys: APIKeys) -> str:
|
121
122
|
return get_authenticated_user(keys.manifold_api_key.get_secret_value()).url
|
123
|
+
|
124
|
+
@staticmethod
|
125
|
+
def get_user_id(api_keys: APIKeys) -> str:
|
126
|
+
return api_keys.manifold_user_id
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import typing as t
|
2
2
|
from datetime import datetime
|
3
3
|
|
4
|
+
from prediction_market_agent_tooling.config import APIKeys
|
4
5
|
from prediction_market_agent_tooling.gtypes import Probability
|
5
6
|
from prediction_market_agent_tooling.markets.agent_market import (
|
6
7
|
AgentMarket,
|
@@ -99,8 +100,12 @@ class MetaculusAgentMarket(AgentMarket):
|
|
99
100
|
|
100
101
|
if len(all_questions) >= limit:
|
101
102
|
break
|
102
|
-
return [MetaculusAgentMarket.from_data_model(q) for q in all_questions]
|
103
|
+
return [MetaculusAgentMarket.from_data_model(q) for q in all_questions[:limit]]
|
103
104
|
|
104
105
|
def submit_prediction(self, p_yes: Probability, reasoning: str) -> None:
|
105
106
|
make_prediction(self.id, p_yes)
|
106
107
|
post_question_comment(self.id, reasoning)
|
108
|
+
|
109
|
+
@staticmethod
|
110
|
+
def get_user_id(api_keys: APIKeys) -> str:
|
111
|
+
return str(api_keys.metaculus_user_id)
|
@@ -1,7 +1,8 @@
|
|
1
1
|
import typing as t
|
2
2
|
from datetime import datetime
|
3
3
|
|
4
|
-
|
4
|
+
import pytz
|
5
|
+
from pydantic import BaseModel, ConfigDict, Field, computed_field
|
5
6
|
from web3 import Web3
|
6
7
|
|
7
8
|
from prediction_market_agent_tooling.gtypes import (
|
@@ -13,6 +14,7 @@ from prediction_market_agent_tooling.gtypes import (
|
|
13
14
|
OmenOutcomeToken,
|
14
15
|
Probability,
|
15
16
|
Wei,
|
17
|
+
wei_type,
|
16
18
|
xDai,
|
17
19
|
)
|
18
20
|
from prediction_market_agent_tooling.markets.data_models import (
|
@@ -37,6 +39,7 @@ INVALID_ANSWER_HEX_BYTES = HexBytes(INVALID_ANSWER)
|
|
37
39
|
INVALID_ANSWER_STR = HexStr(INVALID_ANSWER_HEX_BYTES.hex())
|
38
40
|
OMEN_BASE_URL = "https://aiomen.eth.limo"
|
39
41
|
PRESAGIO_BASE_URL = "https://presagio.pages.dev"
|
42
|
+
TEST_CATEGORY = "test" # This category is hidden on Presagio for testing purposes.
|
40
43
|
|
41
44
|
|
42
45
|
def get_boolean_outcome(outcome_str: str) -> bool:
|
@@ -207,8 +210,6 @@ class OmenMarket(BaseModel):
|
|
207
210
|
creationTimestamp: int
|
208
211
|
condition: Condition
|
209
212
|
question: Question
|
210
|
-
lastActiveDay: int
|
211
|
-
lastActiveHour: int
|
212
213
|
|
213
214
|
@property
|
214
215
|
def openingTimestamp(self) -> int:
|
@@ -218,7 +219,7 @@ class OmenMarket(BaseModel):
|
|
218
219
|
|
219
220
|
@property
|
220
221
|
def opening_datetime(self) -> datetime:
|
221
|
-
return datetime.fromtimestamp(self.openingTimestamp)
|
222
|
+
return datetime.fromtimestamp(self.openingTimestamp, tz=pytz.UTC)
|
222
223
|
|
223
224
|
@property
|
224
225
|
def close_time(self) -> datetime:
|
@@ -376,13 +377,103 @@ class OmenMarket(BaseModel):
|
|
376
377
|
def url(self) -> str:
|
377
378
|
return f"{PRESAGIO_BASE_URL}/markets?id={self.id}"
|
378
379
|
|
380
|
+
@staticmethod
|
381
|
+
def from_created_market(model: "CreatedMarket") -> "OmenMarket":
|
382
|
+
"""
|
383
|
+
OmenMarket is meant to be retrieved from subgraph, however in tests against local chain it's very handy to create it out of `CreatedMarket`,
|
384
|
+
which is collection of events that are emitted during the market creation in omen_create_market_tx function.
|
385
|
+
"""
|
386
|
+
if len(model.market_event.conditionIds) != 1:
|
387
|
+
raise ValueError(
|
388
|
+
f"Unexpected number of conditions: {len(model.market_event.conditionIds)}"
|
389
|
+
)
|
390
|
+
outcome_token_amounts = model.funding_event.outcome_token_amounts
|
391
|
+
return OmenMarket(
|
392
|
+
id=HexAddress(
|
393
|
+
HexStr(model.market_event.fixedProductMarketMaker.lower())
|
394
|
+
), # Lowering to be identical with subgraph's output.
|
395
|
+
title=model.question_event.parsed_question.question,
|
396
|
+
creator=HexAddress(
|
397
|
+
HexStr(model.market_event.creator.lower())
|
398
|
+
), # Lowering to be identical with subgraph's output.
|
399
|
+
category=model.question_event.parsed_question.category,
|
400
|
+
collateralVolume=Wei(0), # No volume possible yet.
|
401
|
+
liquidityParameter=calculate_liquidity_parameter(outcome_token_amounts),
|
402
|
+
usdVolume=USD(0), # No volume possible yet.
|
403
|
+
fee=model.fee,
|
404
|
+
collateralToken=HexAddress(
|
405
|
+
HexStr(model.market_event.collateralToken.lower())
|
406
|
+
), # Lowering to be identical with subgraph's output.
|
407
|
+
outcomes=model.question_event.parsed_question.outcomes,
|
408
|
+
outcomeTokenAmounts=outcome_token_amounts,
|
409
|
+
outcomeTokenMarginalPrices=calculate_marginal_prices(outcome_token_amounts),
|
410
|
+
answerFinalizedTimestamp=None, # It's a fresh market.
|
411
|
+
currentAnswer=None, # It's a fresh market.
|
412
|
+
creationTimestamp=model.market_creation_timestamp,
|
413
|
+
condition=Condition(
|
414
|
+
id=model.market_event.conditionIds[0],
|
415
|
+
outcomeSlotCount=len(model.question_event.parsed_question.outcomes),
|
416
|
+
),
|
417
|
+
question=Question(
|
418
|
+
id=model.question_event.question_id,
|
419
|
+
title=model.question_event.parsed_question.question,
|
420
|
+
data=model.question_event.question, # Question in the event holds the "raw" data.
|
421
|
+
templateId=model.question_event.template_id,
|
422
|
+
outcomes=model.question_event.parsed_question.outcomes,
|
423
|
+
isPendingArbitration=False, # Can not be, it's a fresh market.
|
424
|
+
openingTimestamp=model.question_event.opening_ts,
|
425
|
+
answerFinalizedTimestamp=None, # It's a new one, can not be.
|
426
|
+
currentAnswer=None, # It's a new one, no answer yet.
|
427
|
+
),
|
428
|
+
)
|
429
|
+
|
430
|
+
|
431
|
+
def calculate_liquidity_parameter(
|
432
|
+
outcome_token_amounts: list[OmenOutcomeToken],
|
433
|
+
) -> Wei:
|
434
|
+
"""
|
435
|
+
Converted to Python from https://github.com/protofire/omen-subgraph/blob/f92bbfb6fa31ed9cd5985c416a26a2f640837d8b/src/utils/fpmm.ts#L171.
|
436
|
+
"""
|
437
|
+
amounts_product = 1.0
|
438
|
+
for amount in outcome_token_amounts:
|
439
|
+
amounts_product *= amount
|
440
|
+
n = len(outcome_token_amounts)
|
441
|
+
liquidity_parameter = amounts_product ** (1.0 / n)
|
442
|
+
return wei_type(liquidity_parameter)
|
443
|
+
|
444
|
+
|
445
|
+
def calculate_marginal_prices(
|
446
|
+
outcome_token_amounts: list[OmenOutcomeToken],
|
447
|
+
) -> list[xDai] | None:
|
448
|
+
"""
|
449
|
+
Converted to Python from https://github.com/protofire/omen-subgraph/blob/f92bbfb6fa31ed9cd5985c416a26a2f640837d8b/src/utils/fpmm.ts#L197.
|
450
|
+
"""
|
451
|
+
all_non_zero = all(x != 0 for x in outcome_token_amounts)
|
452
|
+
if not all_non_zero:
|
453
|
+
return None
|
454
|
+
|
455
|
+
n_outcomes = len(outcome_token_amounts)
|
456
|
+
weights = []
|
457
|
+
|
458
|
+
for i in range(n_outcomes):
|
459
|
+
weight = 1.0
|
460
|
+
for j in range(n_outcomes):
|
461
|
+
if i != j:
|
462
|
+
weight *= outcome_token_amounts[j]
|
463
|
+
weights.append(weight)
|
464
|
+
|
465
|
+
sum_weights = sum(weights)
|
466
|
+
|
467
|
+
marginal_prices = [weights[i] / sum_weights for i in range(n_outcomes)]
|
468
|
+
return [xDai(mp) for mp in marginal_prices]
|
469
|
+
|
379
470
|
|
380
471
|
class OmenBetCreator(BaseModel):
|
381
472
|
id: HexAddress
|
382
473
|
|
383
474
|
|
384
475
|
class OmenBet(BaseModel):
|
385
|
-
id: HexAddress
|
476
|
+
id: HexAddress # A concatenation of: FPMM contract ID, trader ID and nonce. See https://github.com/protofire/omen-subgraph/blob/f92bbfb6fa31ed9cd5985c416a26a2f640837d8b/src/FixedProductMarketMakerMapping.ts#L109
|
386
477
|
title: str
|
387
478
|
collateralToken: HexAddress
|
388
479
|
outcomeTokenMarginalPrice: xDai
|
@@ -400,7 +491,7 @@ class OmenBet(BaseModel):
|
|
400
491
|
|
401
492
|
@property
|
402
493
|
def creation_datetime(self) -> datetime:
|
403
|
-
return datetime.fromtimestamp(self.creationTimestamp)
|
494
|
+
return datetime.fromtimestamp(self.creationTimestamp, tz=pytz.UTC)
|
404
495
|
|
405
496
|
@property
|
406
497
|
def boolean_outcome(self) -> bool:
|
@@ -431,6 +522,9 @@ class OmenBet(BaseModel):
|
|
431
522
|
|
432
523
|
def to_bet(self) -> Bet:
|
433
524
|
return Bet(
|
525
|
+
id=str(
|
526
|
+
self.transactionHash
|
527
|
+
), # 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.
|
434
528
|
amount=BetAmount(amount=self.collateralAmountUSD, currency=Currency.xDai),
|
435
529
|
outcome=self.boolean_outcome,
|
436
530
|
created_time=self.creation_datetime,
|
@@ -445,6 +539,9 @@ class OmenBet(BaseModel):
|
|
445
539
|
)
|
446
540
|
|
447
541
|
return ResolvedBet(
|
542
|
+
id=str(
|
543
|
+
self.transactionHash
|
544
|
+
), # 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.
|
448
545
|
amount=BetAmount(amount=self.collateralAmountUSD, currency=Currency.xDai),
|
449
546
|
outcome=self.boolean_outcome,
|
450
547
|
created_time=self.creation_datetime,
|
@@ -527,3 +624,147 @@ class RealityAnswers(BaseModel):
|
|
527
624
|
|
528
625
|
class RealityAnswersResponse(BaseModel):
|
529
626
|
data: RealityAnswers
|
627
|
+
|
628
|
+
|
629
|
+
def format_realitio_question(
|
630
|
+
question: str,
|
631
|
+
outcomes: list[str],
|
632
|
+
category: str,
|
633
|
+
language: str,
|
634
|
+
template_id: int,
|
635
|
+
) -> str:
|
636
|
+
"""If you add a new template id here, also add to the parsing function below."""
|
637
|
+
if template_id == 2:
|
638
|
+
return "␟".join(
|
639
|
+
[
|
640
|
+
question,
|
641
|
+
",".join(f'"{o}"' for o in outcomes),
|
642
|
+
category,
|
643
|
+
language,
|
644
|
+
]
|
645
|
+
)
|
646
|
+
|
647
|
+
raise ValueError(f"Unsupported template id {template_id}.")
|
648
|
+
|
649
|
+
|
650
|
+
def parse_realitio_question(question_raw: str, template_id: int) -> "ParsedQuestion":
|
651
|
+
"""If you add a new template id here, also add to the encoding function above."""
|
652
|
+
if template_id == 2:
|
653
|
+
question, outcomes_raw, category, language = question_raw.split("␟")
|
654
|
+
outcomes = [o.strip('"') for o in outcomes_raw.split(",")]
|
655
|
+
return ParsedQuestion(
|
656
|
+
question=question, outcomes=outcomes, category=category, language=language
|
657
|
+
)
|
658
|
+
|
659
|
+
raise ValueError(f"Unsupported template id {template_id}.")
|
660
|
+
|
661
|
+
|
662
|
+
class ParsedQuestion(BaseModel):
|
663
|
+
question: str
|
664
|
+
outcomes: list[str]
|
665
|
+
language: str
|
666
|
+
category: str
|
667
|
+
|
668
|
+
|
669
|
+
class RealitioLogNewQuestionEvent(BaseModel):
|
670
|
+
question_id: HexBytes
|
671
|
+
user: HexAddress
|
672
|
+
template_id: int
|
673
|
+
question: str # Be aware, this is question in format of format_realitio_question function, it's raw data.
|
674
|
+
content_hash: HexBytes
|
675
|
+
arbitrator: HexAddress
|
676
|
+
timeout: int
|
677
|
+
opening_ts: int
|
678
|
+
nonce: int
|
679
|
+
created: int
|
680
|
+
|
681
|
+
@property
|
682
|
+
def user_checksummed(self) -> ChecksumAddress:
|
683
|
+
return Web3.to_checksum_address(self.user)
|
684
|
+
|
685
|
+
@property
|
686
|
+
def parsed_question(self) -> ParsedQuestion:
|
687
|
+
return parse_realitio_question(
|
688
|
+
question_raw=self.question, template_id=self.template_id
|
689
|
+
)
|
690
|
+
|
691
|
+
|
692
|
+
class OmenFixedProductMarketMakerCreationEvent(BaseModel):
|
693
|
+
creator: HexAddress
|
694
|
+
fixedProductMarketMaker: HexAddress
|
695
|
+
conditionalTokens: HexAddress
|
696
|
+
collateralToken: HexAddress
|
697
|
+
conditionIds: list[HexBytes]
|
698
|
+
fee: int
|
699
|
+
|
700
|
+
@property
|
701
|
+
def creator_checksummed(self) -> ChecksumAddress:
|
702
|
+
return Web3.to_checksum_address(self.creator)
|
703
|
+
|
704
|
+
@property
|
705
|
+
def fixed_product_market_maker_checksummed(self) -> ChecksumAddress:
|
706
|
+
return Web3.to_checksum_address(self.fixedProductMarketMaker)
|
707
|
+
|
708
|
+
@property
|
709
|
+
def conditional_tokens_checksummed(self) -> ChecksumAddress:
|
710
|
+
return Web3.to_checksum_address(self.conditionalTokens)
|
711
|
+
|
712
|
+
@property
|
713
|
+
def collateral_token_checksummed(self) -> ChecksumAddress:
|
714
|
+
return Web3.to_checksum_address(self.collateralToken)
|
715
|
+
|
716
|
+
|
717
|
+
class ConditionPreparationEvent(BaseModel):
|
718
|
+
conditionId: HexBytes
|
719
|
+
oracle: HexAddress
|
720
|
+
questionId: HexBytes
|
721
|
+
outcomeSlotCount: int
|
722
|
+
|
723
|
+
|
724
|
+
class FPMMFundingAddedEvent(BaseModel):
|
725
|
+
funder: HexAddress
|
726
|
+
amountsAdded: list[OmenOutcomeToken]
|
727
|
+
sharesMinted: Wei
|
728
|
+
|
729
|
+
@property
|
730
|
+
def outcome_token_amounts(self) -> list[OmenOutcomeToken]:
|
731
|
+
# Just renaming so we remember what it is.
|
732
|
+
return self.amountsAdded
|
733
|
+
|
734
|
+
|
735
|
+
class CreatedMarket(BaseModel):
|
736
|
+
market_creation_timestamp: int
|
737
|
+
market_event: OmenFixedProductMarketMakerCreationEvent
|
738
|
+
funding_event: FPMMFundingAddedEvent
|
739
|
+
condition_id: HexBytes
|
740
|
+
question_event: RealitioLogNewQuestionEvent
|
741
|
+
condition_event: ConditionPreparationEvent | None
|
742
|
+
initial_funds: Wei
|
743
|
+
fee: Wei
|
744
|
+
distribution_hint: list[OmenOutcomeToken] | None
|
745
|
+
|
746
|
+
|
747
|
+
class ContractPrediction(BaseModel):
|
748
|
+
model_config = ConfigDict(populate_by_name=True)
|
749
|
+
publisher: str = Field(..., alias="publisherAddress")
|
750
|
+
ipfs_hash: HexBytes = Field(..., alias="ipfsHash")
|
751
|
+
tx_hashes: list[HexBytes] = Field(..., alias="txHashes")
|
752
|
+
estimated_probability_bps: int = Field(..., alias="estimatedProbabilityBps")
|
753
|
+
|
754
|
+
@computed_field # type: ignore[prop-decorator] # Mypy issue: https://github.com/python/mypy/issues/14461
|
755
|
+
@property
|
756
|
+
def publisher_checksummed(self) -> ChecksumAddress:
|
757
|
+
return Web3.to_checksum_address(self.publisher)
|
758
|
+
|
759
|
+
@staticmethod
|
760
|
+
def from_tuple(values: tuple[t.Any]) -> "ContractPrediction":
|
761
|
+
data = {k: v for k, v in zip(ContractPrediction.model_fields.keys(), values)}
|
762
|
+
return ContractPrediction.model_validate(data)
|
763
|
+
|
764
|
+
|
765
|
+
class IPFSAgentResult(BaseModel):
|
766
|
+
reasoning: str
|
767
|
+
|
768
|
+
model_config = ConfigDict(
|
769
|
+
extra="forbid",
|
770
|
+
)
|