prediction-market-agent-tooling 0.16.0__tar.gz → 0.18.0__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.
Files changed (72) hide show
  1. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/PKG-INFO +2 -1
  2. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/benchmark/agents.py +5 -2
  3. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/benchmark/utils.py +2 -3
  4. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/config.py +32 -0
  5. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/deploy/agent.py +44 -3
  6. prediction_market_agent_tooling-0.18.0/prediction_market_agent_tooling/deploy/agent_example.py +28 -0
  7. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/omen/omen.py +32 -16
  8. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +44 -32
  9. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +14 -4
  10. prediction_market_agent_tooling-0.18.0/prediction_market_agent_tooling/monitor/langfuse/langfuse_wrapper.py +26 -0
  11. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/monitor/monitor.py +9 -5
  12. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/balances.py +8 -4
  13. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/contract.py +17 -0
  14. prediction_market_agent_tooling-0.18.0/prediction_market_agent_tooling/tools/gnosis_rpc.py +6 -0
  15. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/web3_utils.py +64 -14
  16. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/pyproject.toml +2 -1
  17. prediction_market_agent_tooling-0.16.0/prediction_market_agent_tooling/deploy/agent_example.py +0 -18
  18. prediction_market_agent_tooling-0.16.0/prediction_market_agent_tooling/tools/gnosis_rpc.py +0 -24
  19. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/LICENSE +0 -0
  20. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/README.md +0 -0
  21. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
  22. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
  23. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
  24. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
  25. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
  26. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
  27. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
  28. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
  29. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/abis/wxdai.abi.json +0 -0
  30. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
  31. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
  32. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/deploy/constants.py +0 -0
  33. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
  34. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
  35. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
  36. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/gtypes.py +0 -0
  37. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/agent_market.py +0 -0
  38. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/categorize.py +0 -0
  39. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/data_models.py +0 -0
  40. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
  41. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
  42. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
  43. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/manifold/manifold.py +0 -0
  44. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
  45. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/markets.py +0 -0
  46. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
  47. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/omen/data_models.py +0 -0
  48. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +0 -0
  49. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
  50. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
  51. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +0 -0
  52. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
  53. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
  54. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/monitor/markets/manifold.py +0 -0
  55. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/monitor/markets/omen.py +0 -0
  56. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/monitor/markets/polymarket.py +0 -0
  57. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/monitor/monitor_app.py +0 -0
  58. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/monitor/monitor_settings.py +0 -0
  59. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/py.typed +0 -0
  60. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
  61. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +0 -0
  62. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +0 -0
  63. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
  64. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/cache.py +0 -0
  65. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/costs.py +0 -0
  66. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/google.py +0 -0
  67. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
  68. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
  69. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
  70. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/safe.py +0 -0
  71. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/singleton.py +0 -0
  72. {prediction_market_agent_tooling-0.16.0 → prediction_market_agent_tooling-0.18.0}/prediction_market_agent_tooling/tools/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prediction-market-agent-tooling
3
- Version: 0.16.0
3
+ Version: 0.18.0
4
4
  Summary: Tools to benchmark, deploy and monitor prediction market agents.
5
5
  Author: Gnosis
6
6
  Requires-Python: >=3.10,<3.12
@@ -22,6 +22,7 @@ Requires-Dist: isort (>=5.13.2,<6.0.0)
22
22
  Requires-Dist: langchain (>=0.1.9,<0.2.0) ; extra == "langchain"
23
23
  Requires-Dist: langchain-community (>=0.0.19)
24
24
  Requires-Dist: langchain-openai (>=0.0.5,<0.0.6) ; extra == "langchain"
25
+ Requires-Dist: langfuse (>=2.27.1,<3.0.0)
25
26
  Requires-Dist: loguru (>=0.7.2,<0.8.0)
26
27
  Requires-Dist: mech-client (>=0.2.13,<0.3.0)
27
28
  Requires-Dist: numpy (>=1.26.4,<2.0.0)
@@ -6,6 +6,7 @@ from prediction_market_agent_tooling.benchmark.utils import (
6
6
  OutcomePrediction,
7
7
  Prediction,
8
8
  )
9
+ from prediction_market_agent_tooling.gtypes import Probability
9
10
 
10
11
 
11
12
  class AbstractBenchmarkedAgent:
@@ -86,7 +87,8 @@ class RandomAgent(AbstractBenchmarkedAgent):
86
87
  p_yes, confidence = random.random(), random.random()
87
88
  return Prediction(
88
89
  outcome_prediction=OutcomePrediction(
89
- p_yes=p_yes,
90
+ decision=p_yes > 0.5,
91
+ p_yes=Probability(p_yes),
90
92
  confidence=confidence,
91
93
  info_utility=None,
92
94
  ),
@@ -109,7 +111,8 @@ class FixedAgent(AbstractBenchmarkedAgent):
109
111
  p_yes, confidence = 1.0 if self.fixed_answer else 0.0, 1.0
110
112
  return Prediction(
111
113
  outcome_prediction=OutcomePrediction(
112
- p_yes=p_yes,
114
+ decision=self.fixed_answer,
115
+ p_yes=Probability(p_yes),
113
116
  confidence=confidence,
114
117
  info_utility=None,
115
118
  ),
@@ -3,12 +3,11 @@ import typing as t
3
3
 
4
4
  from pydantic import BaseModel
5
5
 
6
+ from prediction_market_agent_tooling.deploy.agent import Answer
6
7
  from prediction_market_agent_tooling.markets.data_models import Resolution
7
8
 
8
9
 
9
- class OutcomePrediction(BaseModel):
10
- p_yes: float
11
- confidence: float
10
+ class OutcomePrediction(Answer):
12
11
  info_utility: t.Optional[float]
13
12
 
14
13
  @property
@@ -1,5 +1,7 @@
1
1
  import typing as t
2
2
 
3
+ from gnosis.eth import EthereumClient
4
+ from gnosis.safe import Safe
3
5
  from pydantic import BaseModel
4
6
  from pydantic.types import SecretStr
5
7
  from pydantic_settings import BaseSettings, SettingsConfigDict
@@ -30,6 +32,10 @@ class APIKeys(BaseSettings):
30
32
  GOOGLE_SEARCH_API_KEY: t.Optional[SecretStr] = None
31
33
  GOOGLE_SEARCH_ENGINE_ID: t.Optional[SecretStr] = None
32
34
 
35
+ LANGFUSE_SECRET_KEY: t.Optional[SecretStr] = None
36
+ LANGFUSE_PUBLIC_KEY: t.Optional[SecretStr] = None
37
+ LANGFUSE_HOST: t.Optional[str] = None
38
+
33
39
  ENABLE_CACHE: bool = True
34
40
  CACHE_DIR: str = "./.cache"
35
41
 
@@ -72,6 +78,24 @@ class APIKeys(BaseSettings):
72
78
  "GOOGLE_SEARCH_ENGINE_ID missing in the environment.",
73
79
  )
74
80
 
81
+ @property
82
+ def langfuse_secret_key(self) -> SecretStr:
83
+ return check_not_none(
84
+ self.LANGFUSE_SECRET_KEY, "LANGFUSE_SECRET_KEY missing in the environment."
85
+ )
86
+
87
+ @property
88
+ def langfuse_public_key(self) -> SecretStr:
89
+ return check_not_none(
90
+ self.LANGFUSE_PUBLIC_KEY, "LANGFUSE_PUBLIC_KEY missing in the environment."
91
+ )
92
+
93
+ @property
94
+ def langfuse_host(self) -> str:
95
+ return check_not_none(
96
+ self.LANGFUSE_HOST, "LANGFUSE_HOST missing in the environment."
97
+ )
98
+
75
99
  def model_dump_public(self) -> dict[str, t.Any]:
76
100
  return {
77
101
  k: v
@@ -110,3 +134,11 @@ class PrivateCredentials(BaseModel):
110
134
  private_key=api_keys.bet_from_private_key,
111
135
  safe_address=api_keys.SAFE_ADDRESS,
112
136
  )
137
+
138
+ def check_if_is_safe_owner(self, ethereum_client: EthereumClient) -> bool:
139
+ if not self.safe_address:
140
+ raise ValueError("Cannot check ownership if safe_address is not defined.")
141
+
142
+ s = Safe(self.safe_address, ethereum_client) # type: ignore[abstract]
143
+ public_key_from_signer = private_key_to_public_key(self.private_key)
144
+ return s.retrieve_is_owner(public_key_from_signer)
@@ -6,6 +6,8 @@ import typing as t
6
6
  from datetime import datetime
7
7
 
8
8
  from loguru import logger
9
+ from pydantic import BaseModel, BeforeValidator
10
+ from typing_extensions import Annotated
9
11
 
10
12
  from prediction_market_agent_tooling.config import APIKeys, PrivateCredentials
11
13
  from prediction_market_agent_tooling.deploy.constants import (
@@ -21,6 +23,7 @@ from prediction_market_agent_tooling.deploy.gcp.utils import (
21
23
  gcp_function_is_active,
22
24
  gcp_resolve_api_keys_secrets,
23
25
  )
26
+ from prediction_market_agent_tooling.gtypes import Probability
24
27
  from prediction_market_agent_tooling.markets.agent_market import (
25
28
  AgentMarket,
26
29
  FilterBy,
@@ -31,6 +34,9 @@ from prediction_market_agent_tooling.markets.markets import MarketType
31
34
  from prediction_market_agent_tooling.markets.omen.omen import (
32
35
  redeem_from_all_user_positions,
33
36
  )
37
+ from prediction_market_agent_tooling.monitor.langfuse.langfuse_wrapper import (
38
+ LangfuseWrapper,
39
+ )
34
40
  from prediction_market_agent_tooling.monitor.monitor_app import (
35
41
  MARKET_TYPE_TO_DEPLOYED_AGENT,
36
42
  )
@@ -39,8 +45,43 @@ from prediction_market_agent_tooling.tools.utils import DatetimeWithTimezone, ut
39
45
  MAX_AVAILABLE_MARKETS = 20
40
46
 
41
47
 
48
+ def to_boolean_outcome(value: str | bool) -> bool:
49
+ if isinstance(value, bool):
50
+ return value
51
+
52
+ elif isinstance(value, str):
53
+ value = value.lower().strip()
54
+
55
+ if value in {"true", "yes", "y", "1"}:
56
+ return True
57
+
58
+ elif value in {"false", "no", "n", "0"}:
59
+ return False
60
+
61
+ else:
62
+ raise ValueError(f"Expected a boolean string, but got {value}")
63
+
64
+ else:
65
+ raise ValueError(f"Expected a boolean or a string, but got {value}")
66
+
67
+
68
+ Decision = Annotated[bool, BeforeValidator(to_boolean_outcome)]
69
+
70
+
71
+ class Answer(BaseModel):
72
+ decision: Decision # Warning: p_yes > 0.5 doesn't necessarily mean decision is True! For example, if our p_yes is 55%, but market's p_yes is 80%, then it might be profitable to bet on False.
73
+ p_yes: Probability
74
+ confidence: float
75
+ reasoning: str | None = None
76
+
77
+ @property
78
+ def p_no(self) -> Probability:
79
+ return Probability(1 - self.p_yes)
80
+
81
+
42
82
  class DeployableAgent:
43
83
  def __init__(self) -> None:
84
+ self.langfuse_wrapper = LangfuseWrapper(agent_name=self.__class__.__name__)
44
85
  self.load()
45
86
 
46
87
  def __init_subclass__(cls, **kwargs: t.Any) -> None:
@@ -58,7 +99,7 @@ class DeployableAgent:
58
99
  """
59
100
  return markets[:1]
60
101
 
61
- def answer_binary_market(self, market: AgentMarket) -> bool | None:
102
+ def answer_binary_market(self, market: AgentMarket) -> Answer | None:
62
103
  """
63
104
  Answer the binary market. This method must be implemented by the subclass.
64
105
  """
@@ -157,7 +198,7 @@ def {entrypoint_function_name}(request) -> str:
157
198
  if cron_schedule:
158
199
  schedule_deployed_gcp_function(fname, cron_schedule=cron_schedule)
159
200
 
160
- def calculate_bet_amount(self, answer: bool, market: AgentMarket) -> BetAmount:
201
+ def calculate_bet_amount(self, answer: Answer, market: AgentMarket) -> BetAmount:
161
202
  """
162
203
  Calculate the bet amount. By default, it returns the minimum bet amount.
163
204
  """
@@ -205,7 +246,7 @@ def {entrypoint_function_name}(request) -> str:
205
246
  )
206
247
  market.place_bet(
207
248
  amount=amount,
208
- outcome=result,
249
+ outcome=result.decision,
209
250
  )
210
251
 
211
252
  def after(self, market_type: MarketType) -> None:
@@ -0,0 +1,28 @@
1
+ import random
2
+ import typing as t
3
+
4
+ from prediction_market_agent_tooling.deploy.agent import (
5
+ Answer,
6
+ DeployableAgent,
7
+ Probability,
8
+ )
9
+ from prediction_market_agent_tooling.markets.agent_market import AgentMarket
10
+
11
+
12
+ class DeployableCoinFlipAgent(DeployableAgent):
13
+ def pick_markets(self, markets: t.Sequence[AgentMarket]) -> t.Sequence[AgentMarket]:
14
+ return random.sample(markets, 1)
15
+
16
+ def answer_binary_market(self, market: AgentMarket) -> Answer | None:
17
+ decision = random.choice([True, False])
18
+ return Answer(
19
+ decision=decision,
20
+ p_yes=Probability(float(decision)),
21
+ confidence=0.5,
22
+ reasoning="I flipped a coin to decide.",
23
+ )
24
+
25
+
26
+ class DeployableAlwaysRaiseAgent(DeployableAgent):
27
+ def answer_binary_market(self, market: AgentMarket) -> Answer | None:
28
+ raise RuntimeError("I always raise!")
@@ -432,6 +432,7 @@ def omen_sell_outcome_tx(
432
432
  market: OmenAgentMarket,
433
433
  outcome: str,
434
434
  auto_withdraw: bool,
435
+ web3: Web3 | None = None,
435
436
  ) -> None:
436
437
  """
437
438
  Sells the given xDai value of shares corresponding to the given outcome in
@@ -447,7 +448,10 @@ def omen_sell_outcome_tx(
447
448
  collateral_token = OmenCollateralTokenContract()
448
449
 
449
450
  # Verify, that markets uses conditional tokens that we expect.
450
- if market_contract.conditionalTokens() != conditional_token_contract.address:
451
+ if (
452
+ market_contract.conditionalTokens(web3=web3)
453
+ != conditional_token_contract.address
454
+ ):
451
455
  raise ValueError(
452
456
  f"Market {market.id} uses conditional token that we didn't expect, {market_contract.conditionalTokens()} != {conditional_token_contract.address=}"
453
457
  )
@@ -457,7 +461,7 @@ def omen_sell_outcome_tx(
457
461
 
458
462
  # Calculate the amount of shares we will sell for the given selling amount of xdai.
459
463
  max_outcome_tokens_to_sell = market_contract.calcSellAmount(
460
- amount_wei, outcome_index
464
+ amount_wei, outcome_index, web3=web3
461
465
  )
462
466
  # Allow 1% slippage.
463
467
  max_outcome_tokens_to_sell = add_fraction(max_outcome_tokens_to_sell, 0.01)
@@ -467,6 +471,7 @@ def omen_sell_outcome_tx(
467
471
  private_credentials=private_credentials,
468
472
  for_address=market_contract.address,
469
473
  approve=True,
474
+ web3=web3,
470
475
  )
471
476
  # Sell the shares.
472
477
  market_contract.sell(
@@ -474,12 +479,12 @@ def omen_sell_outcome_tx(
474
479
  amount_wei,
475
480
  outcome_index,
476
481
  max_outcome_tokens_to_sell,
482
+ web3=web3,
477
483
  )
478
484
  if auto_withdraw:
479
485
  # Optionally, withdraw from the collateral token back to the `from_address` wallet.
480
486
  collateral_token.withdraw(
481
- private_credentials=private_credentials,
482
- amount_wei=amount_wei,
487
+ private_credentials=private_credentials, amount_wei=amount_wei, web3=web3
483
488
  )
484
489
 
485
490
 
@@ -489,6 +494,7 @@ def binary_omen_sell_outcome_tx(
489
494
  market: OmenAgentMarket,
490
495
  binary_outcome: bool,
491
496
  auto_withdraw: bool,
497
+ web3: Web3 | None = None,
492
498
  ) -> None:
493
499
  omen_sell_outcome_tx(
494
500
  private_credentials=private_credentials,
@@ -496,6 +502,7 @@ def binary_omen_sell_outcome_tx(
496
502
  market=market,
497
503
  outcome=OMEN_TRUE_OUTCOME if binary_outcome else OMEN_FALSE_OUTCOME,
498
504
  auto_withdraw=auto_withdraw,
505
+ web3=web3,
499
506
  )
500
507
 
501
508
 
@@ -509,6 +516,7 @@ def omen_create_market_tx(
509
516
  outcomes: list[str],
510
517
  auto_deposit: bool,
511
518
  fee: float = OMEN_DEFAULT_MARKET_FEE,
519
+ web3: Web3 | None = None,
512
520
  ) -> ChecksumAddress:
513
521
  """
514
522
  Based on omen-exchange TypeScript code: https://github.com/protofire/omen-exchange/blob/b0b9a3e71b415d6becf21fe428e1c4fc0dad2e80/app/src/services/cpk/cpk.ts#L308
@@ -539,19 +547,22 @@ def omen_create_market_tx(
539
547
  private_credentials=private_credentials,
540
548
  for_address=factory_contract.address,
541
549
  amount_wei=initial_funds_wei,
550
+ web3=web3,
542
551
  )
543
552
 
544
553
  # Deposit xDai to the collateral token,
545
554
  # this can be skipped, if we know we already have enough collateral tokens.
546
555
  collateral_token_balance = collateral_token_contract.balanceOf(
547
- for_address=from_address,
556
+ for_address=from_address, web3=web3
548
557
  )
549
558
  if (
550
559
  auto_deposit
551
560
  and initial_funds_wei > 0
552
561
  and collateral_token_balance < initial_funds_wei
553
562
  ):
554
- collateral_token_contract.deposit(private_credentials, initial_funds_wei)
563
+ collateral_token_contract.deposit(
564
+ private_credentials, initial_funds_wei, web3=web3
565
+ )
555
566
 
556
567
  # Create the question on Realitio.
557
568
  question_id = realitio_contract.askQuestion(
@@ -562,6 +573,7 @@ def omen_create_market_tx(
562
573
  language=language,
563
574
  arbitrator=Arbitrator.KLEROS,
564
575
  opening=closing_time, # The question is opened at the closing time of the market.
576
+ web3=web3,
565
577
  )
566
578
 
567
579
  # Construct the condition id.
@@ -569,13 +581,15 @@ def omen_create_market_tx(
569
581
  question_id=question_id,
570
582
  oracle_address=oracle_contract.address,
571
583
  outcomes_slot_count=len(outcomes),
584
+ web3=web3,
572
585
  )
573
- if not conditional_token_contract.does_condition_exists(condition_id):
586
+ if not conditional_token_contract.does_condition_exists(condition_id, web3=web3):
574
587
  conditional_token_contract.prepareCondition(
575
588
  private_credentials=private_credentials,
576
589
  question_id=question_id,
577
590
  oracle_address=oracle_contract.address,
578
591
  outcomes_slot_count=len(outcomes),
592
+ web3=web3,
579
593
  )
580
594
 
581
595
  # Create the market.
@@ -584,6 +598,7 @@ def omen_create_market_tx(
584
598
  condition_id=condition_id,
585
599
  fee=fee,
586
600
  initial_funds_wei=initial_funds_wei,
601
+ web3=web3,
587
602
  )
588
603
 
589
604
  # Note: In the Omen's Typescript code, there is futher a creation of `stakingRewardsFactoryAddress`,
@@ -602,6 +617,7 @@ def omen_fund_market_tx(
602
617
  market: OmenAgentMarket,
603
618
  funds: Wei,
604
619
  auto_deposit: bool,
620
+ web3: Web3 | None = None,
605
621
  ) -> None:
606
622
  from_address = private_credentials.public_key
607
623
  market_contract = market.get_contract()
@@ -611,20 +627,19 @@ def omen_fund_market_tx(
611
627
  # this can be skipped, if we know we already have enough collateral tokens.
612
628
  if (
613
629
  auto_deposit
614
- and collateral_token_contract.balanceOf(
615
- for_address=from_address,
616
- )
630
+ and collateral_token_contract.balanceOf(for_address=from_address, web3=web3)
617
631
  < funds
618
632
  ):
619
- collateral_token_contract.deposit(private_credentials, funds)
633
+ collateral_token_contract.deposit(private_credentials, funds, web3=web3)
620
634
 
621
635
  collateral_token_contract.approve(
622
636
  private_credentials=private_credentials,
623
637
  for_address=market_contract.address,
624
638
  amount_wei=funds,
639
+ web3=web3,
625
640
  )
626
641
 
627
- market_contract.addFunding(private_credentials, funds)
642
+ market_contract.addFunding(private_credentials, funds, web3=web3)
628
643
 
629
644
 
630
645
  def build_parent_collection_id() -> HexStr:
@@ -727,7 +742,7 @@ def omen_remove_fund_market_tx(
727
742
  """
728
743
  from_address = private_credentials.public_key
729
744
  market_contract = market.get_contract()
730
- original_balances = get_balances(from_address)
745
+ original_balances = get_balances(from_address, web3=web3)
731
746
 
732
747
  total_shares = market_contract.balanceOf(from_address, web3=web3)
733
748
  if total_shares == 0:
@@ -763,7 +778,8 @@ def omen_remove_fund_market_tx(
763
778
  amount=amount_to_merge,
764
779
  web3=web3,
765
780
  )
766
- new_balances = get_balances(from_address)
781
+
782
+ new_balances = get_balances(from_address, web3)
767
783
 
768
784
  logger.debug(f"Result from merge positions {result}")
769
785
  logger.info(
@@ -800,7 +816,7 @@ def redeem_from_all_user_positions(
800
816
  f"[{index+1} / {len(user_positions)}] Processing redeem from {user_position.id=}."
801
817
  )
802
818
 
803
- original_balances = get_balances(public_key)
819
+ original_balances = get_balances(public_key, web3)
804
820
  conditional_token_contract.redeemPositions(
805
821
  private_credentials=private_credentials,
806
822
  collateral_token_address=user_position.position.collateral_token_contract_address_checksummed,
@@ -809,7 +825,7 @@ def redeem_from_all_user_positions(
809
825
  index_sets=user_position.position.indexSets,
810
826
  web3=web3,
811
827
  )
812
- new_balances = get_balances(public_key)
828
+ new_balances = get_balances(public_key, web3)
813
829
 
814
830
  logger.info(
815
831
  f"Redeemed {new_balances.wxdai - original_balances.wxdai} wxDai from position {user_position.id=}."
@@ -56,6 +56,7 @@ class OmenOracleContract(ContractOnGnosisChain):
56
56
  template_id: int,
57
57
  question_raw: str,
58
58
  n_outcomes: int,
59
+ web3: Web3 | None = None,
59
60
  ) -> TxReceipt:
60
61
  return self.send(
61
62
  private_credentials=private_credentials,
@@ -66,6 +67,7 @@ class OmenOracleContract(ContractOnGnosisChain):
66
67
  question=question_raw,
67
68
  numOutcomes=n_outcomes,
68
69
  ),
70
+ web3=web3,
69
71
  )
70
72
 
71
73
 
@@ -86,11 +88,13 @@ class OmenConditionalTokenContract(ContractOnGnosisChain):
86
88
  question_id: HexBytes,
87
89
  oracle_address: ChecksumAddress,
88
90
  outcomes_slot_count: int,
91
+ web3: Web3 | None = None,
89
92
  ) -> HexBytes:
90
93
  id_ = HexBytes(
91
94
  self.call(
92
95
  "getConditionId",
93
96
  [oracle_address, question_id, outcomes_slot_count],
97
+ web3=web3,
94
98
  )
95
99
  )
96
100
  return id_
@@ -177,34 +181,29 @@ class OmenConditionalTokenContract(ContractOnGnosisChain):
177
181
  )
178
182
 
179
183
  def getOutcomeSlotCount(
180
- self,
181
- condition_id: HexBytes,
184
+ self, condition_id: HexBytes, web3: Web3 | None = None
182
185
  ) -> int:
183
- count: int = self.call(
184
- "getOutcomeSlotCount",
185
- [condition_id],
186
- )
186
+ count: int = self.call("getOutcomeSlotCount", [condition_id], web3=web3)
187
187
  return count
188
188
 
189
189
  def does_condition_exists(
190
- self,
191
- condition_id: HexBytes,
190
+ self, condition_id: HexBytes, web3: Web3 | None = None
192
191
  ) -> bool:
193
- return self.getOutcomeSlotCount(condition_id) > 0
192
+ return self.getOutcomeSlotCount(condition_id, web3=web3) > 0
194
193
 
195
194
  def is_condition_resolved(
196
- self,
197
- condition_id: HexBytes,
195
+ self, condition_id: HexBytes, web3: Web3 | None = None
198
196
  ) -> bool:
199
197
  # from ConditionalTokens.redeemPositions:
200
198
  # uint den = payoutDenominator[conditionId]; require(den > 0, "result for condition not received yet");
201
- payout_for_condition = self.payoutDenominator(condition_id)
199
+ payout_for_condition = self.payoutDenominator(condition_id, web3=web3)
202
200
  return payout_for_condition > 0
203
201
 
204
- def payoutDenominator(self, condition_id: HexBytes) -> int:
202
+ def payoutDenominator(
203
+ self, condition_id: HexBytes, web3: Web3 | None = None
204
+ ) -> int:
205
205
  payoutForCondition: int = self.call(
206
- "payoutDenominator",
207
- [condition_id],
206
+ "payoutDenominator", [condition_id], web3=web3
208
207
  )
209
208
  return payoutForCondition
210
209
 
@@ -214,6 +213,7 @@ class OmenConditionalTokenContract(ContractOnGnosisChain):
214
213
  for_address: ChecksumAddress,
215
214
  approve: bool,
216
215
  tx_params: t.Optional[TxParams] = None,
216
+ web3: Web3 | None = None,
217
217
  ) -> TxReceipt:
218
218
  return self.send(
219
219
  private_credentials=private_credentials,
@@ -223,6 +223,7 @@ class OmenConditionalTokenContract(ContractOnGnosisChain):
223
223
  approve,
224
224
  ],
225
225
  tx_params=tx_params,
226
+ web3=web3,
226
227
  )
227
228
 
228
229
  def prepareCondition(
@@ -232,6 +233,7 @@ class OmenConditionalTokenContract(ContractOnGnosisChain):
232
233
  question_id: HexBytes,
233
234
  outcomes_slot_count: int,
234
235
  tx_params: t.Optional[TxParams] = None,
236
+ web3: Web3 | None = None,
235
237
  ) -> TxReceipt:
236
238
  return self.send(
237
239
  private_credentials=private_credentials,
@@ -242,6 +244,7 @@ class OmenConditionalTokenContract(ContractOnGnosisChain):
242
244
  outcomes_slot_count,
243
245
  ],
244
246
  tx_params=tx_params,
247
+ web3=web3,
245
248
  )
246
249
 
247
250
 
@@ -272,25 +275,18 @@ class OmenFixedProductMarketMakerContract(ContractOnGnosisChain):
272
275
  return calculated_shares
273
276
 
274
277
  def calcSellAmount(
275
- self,
276
- return_amount: Wei,
277
- outcome_index: int,
278
+ self, return_amount: Wei, outcome_index: int, web3: Web3 | None = None
278
279
  ) -> OmenOutcomeToken:
279
280
  """
280
281
  Returns amount of shares we will sell for the requested wei.
281
282
  """
282
283
  calculated_shares: OmenOutcomeToken = self.call(
283
- "calcSellAmount",
284
- [return_amount, outcome_index],
284
+ "calcSellAmount", [return_amount, outcome_index], web3=web3
285
285
  )
286
286
  return calculated_shares
287
287
 
288
- def conditionalTokens(
289
- self,
290
- ) -> HexAddress:
291
- address: HexAddress = self.call(
292
- "conditionalTokens",
293
- )
288
+ def conditionalTokens(self, web3: Web3 | None = None) -> HexAddress:
289
+ address: HexAddress = self.call("conditionalTokens", web3=web3)
294
290
  return address
295
291
 
296
292
  def buy(
@@ -321,6 +317,7 @@ class OmenFixedProductMarketMakerContract(ContractOnGnosisChain):
321
317
  outcome_index: int,
322
318
  max_outcome_tokens_to_sell: OmenOutcomeToken,
323
319
  tx_params: t.Optional[TxParams] = None,
320
+ web3: Web3 | None = None,
324
321
  ) -> TxReceipt:
325
322
  return self.send(
326
323
  private_credentials=private_credentials,
@@ -331,6 +328,7 @@ class OmenFixedProductMarketMakerContract(ContractOnGnosisChain):
331
328
  max_outcome_tokens_to_sell,
332
329
  ],
333
330
  tx_params=tx_params,
331
+ web3=web3,
334
332
  )
335
333
 
336
334
  def addFunding(
@@ -338,6 +336,7 @@ class OmenFixedProductMarketMakerContract(ContractOnGnosisChain):
338
336
  private_credentials: PrivateCredentials,
339
337
  add_funding: Wei,
340
338
  tx_params: t.Optional[TxParams] = None,
339
+ web3: Web3 | None = None,
341
340
  ) -> TxReceipt:
342
341
  """
343
342
  Funding is added in Weis (xDai) and then converted to shares.
@@ -349,6 +348,7 @@ class OmenFixedProductMarketMakerContract(ContractOnGnosisChain):
349
348
  function_name="addFunding",
350
349
  function_params=[add_funding, distribution_hint],
351
350
  tx_params=tx_params,
351
+ web3=web3,
352
352
  )
353
353
 
354
354
  def removeFunding(
@@ -369,9 +369,9 @@ class OmenFixedProductMarketMakerContract(ContractOnGnosisChain):
369
369
  web3=web3,
370
370
  )
371
371
 
372
- def totalSupply(self) -> Wei:
372
+ def totalSupply(self, web3: Web3 | None = None) -> Wei:
373
373
  # This is the liquidity you seen on the Omen website (but in Wei).
374
- total_supply: Wei = self.call("totalSupply")
374
+ total_supply: Wei = self.call("totalSupply", web3=web3)
375
375
  return total_supply
376
376
 
377
377
 
@@ -412,6 +412,7 @@ class OmenFixedProductMarketMakerFactoryContract(ContractOnGnosisChain):
412
412
  initial_funds_wei: Wei,
413
413
  fee: float = OMEN_DEFAULT_MARKET_FEE,
414
414
  tx_params: t.Optional[TxParams] = None,
415
+ web3: Web3 | None = None,
415
416
  ) -> TxReceipt:
416
417
  fee_wei = xdai_to_wei(
417
418
  xdai_type(fee)
@@ -431,6 +432,7 @@ class OmenFixedProductMarketMakerFactoryContract(ContractOnGnosisChain):
431
432
  distributionHint=[],
432
433
  ),
433
434
  tx_params=tx_params,
435
+ web3=web3,
434
436
  )
435
437
 
436
438
 
@@ -498,6 +500,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
498
500
  opening: datetime,
499
501
  nonce: int | None = None,
500
502
  tx_params: t.Optional[TxParams] = None,
503
+ web3: Web3 | None = None,
501
504
  ) -> HexBytes:
502
505
  """
503
506
  After the question is created, you can find it at https://reality.eth.link/app/#!/creator/{from_address}.
@@ -528,6 +531,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
528
531
  ), # Two equal questions need to have different nonces.
529
532
  ),
530
533
  tx_params=tx_params,
534
+ web3=web3,
531
535
  )
532
536
  question_id = HexBytes(
533
537
  receipt_tx["logs"][0]["topics"][1]
@@ -542,6 +546,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
542
546
  outcomes: list[str],
543
547
  bond: Wei,
544
548
  max_previous: Wei | None = None,
549
+ web3: Web3 | None = None,
545
550
  ) -> TxReceipt:
546
551
  if max_previous is None:
547
552
  # If not provided, defaults to 0, which means no checking,
@@ -563,6 +568,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
563
568
  max_previous=max_previous,
564
569
  ),
565
570
  amount_wei=bond,
571
+ web3=web3,
566
572
  )
567
573
 
568
574
  def claimWinnings(
@@ -574,6 +580,7 @@ class OmenRealitioContract(ContractOnGnosisChain):
574
580
  bonds: list[Wei],
575
581
  answers: list[HexBytes],
576
582
  tx_params: t.Optional[TxParams] = None,
583
+ web3: Web3 | None = None,
577
584
  ) -> TxReceipt:
578
585
  return self.send(
579
586
  private_credentials=private_credentials,
@@ -586,17 +593,22 @@ class OmenRealitioContract(ContractOnGnosisChain):
586
593
  answers=answers,
587
594
  ),
588
595
  tx_params=tx_params,
596
+ web3=web3,
589
597
  )
590
598
 
591
- def balanceOf(self, from_address: ChecksumAddress) -> Wei:
592
- balance = wei_type(self.call("balanceOf", [from_address]))
599
+ def balanceOf(
600
+ self,
601
+ from_address: ChecksumAddress,
602
+ web3: Web3 | None = None,
603
+ ) -> Wei:
604
+ balance = wei_type(self.call("balanceOf", [from_address], web3=web3))
593
605
  return balance
594
606
 
595
607
  def withdraw(
596
608
  self,
597
609
  private_credentials: PrivateCredentials,
610
+ web3: Web3 | None = None,
598
611
  ) -> TxReceipt:
599
612
  return self.send(
600
- private_credentials=private_credentials,
601
- function_name="withdraw",
613
+ private_credentials=private_credentials, function_name="withdraw", web3=web3
602
614
  )