prediction-market-agent-tooling 0.61.2.dev479__py3-none-any.whl → 0.62.0__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.
Files changed (50) hide show
  1. prediction_market_agent_tooling/config.py +2 -3
  2. prediction_market_agent_tooling/deploy/agent.py +4 -5
  3. prediction_market_agent_tooling/deploy/betting_strategy.py +53 -69
  4. prediction_market_agent_tooling/gtypes.py +105 -27
  5. prediction_market_agent_tooling/jobs/jobs_models.py +5 -7
  6. prediction_market_agent_tooling/jobs/omen/omen_jobs.py +13 -17
  7. prediction_market_agent_tooling/markets/agent_market.py +96 -53
  8. prediction_market_agent_tooling/markets/blockchain_utils.py +1 -27
  9. prediction_market_agent_tooling/markets/data_models.py +40 -44
  10. prediction_market_agent_tooling/markets/manifold/api.py +2 -6
  11. prediction_market_agent_tooling/markets/manifold/data_models.py +33 -25
  12. prediction_market_agent_tooling/markets/manifold/manifold.py +13 -11
  13. prediction_market_agent_tooling/markets/market_fees.py +6 -2
  14. prediction_market_agent_tooling/markets/omen/data_models.py +66 -57
  15. prediction_market_agent_tooling/markets/omen/omen.py +222 -250
  16. prediction_market_agent_tooling/markets/omen/omen_contracts.py +31 -53
  17. prediction_market_agent_tooling/markets/omen/omen_resolving.py +7 -14
  18. prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +20 -14
  19. prediction_market_agent_tooling/markets/polymarket/data_models.py +3 -3
  20. prediction_market_agent_tooling/markets/polymarket/data_models_web.py +4 -4
  21. prediction_market_agent_tooling/markets/polymarket/polymarket.py +3 -5
  22. prediction_market_agent_tooling/markets/seer/data_models.py +8 -8
  23. prediction_market_agent_tooling/markets/seer/seer.py +85 -71
  24. prediction_market_agent_tooling/markets/seer/seer_contracts.py +10 -5
  25. prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +5 -2
  26. prediction_market_agent_tooling/monitor/monitor.py +2 -2
  27. prediction_market_agent_tooling/tools/_generic_value.py +261 -0
  28. prediction_market_agent_tooling/tools/balances.py +14 -11
  29. prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +12 -10
  30. prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +31 -24
  31. prediction_market_agent_tooling/tools/betting_strategies/utils.py +3 -1
  32. prediction_market_agent_tooling/tools/contract.py +14 -10
  33. prediction_market_agent_tooling/tools/cow/cow_manager.py +3 -4
  34. prediction_market_agent_tooling/tools/cow/cow_order.py +51 -7
  35. prediction_market_agent_tooling/tools/langfuse_client_utils.py +13 -1
  36. prediction_market_agent_tooling/tools/omen/sell_positions.py +6 -3
  37. prediction_market_agent_tooling/tools/safe.py +5 -6
  38. prediction_market_agent_tooling/tools/tokens/auto_deposit.py +36 -27
  39. prediction_market_agent_tooling/tools/tokens/auto_withdraw.py +4 -25
  40. prediction_market_agent_tooling/tools/tokens/main_token.py +2 -2
  41. prediction_market_agent_tooling/tools/tokens/token_utils.py +46 -0
  42. prediction_market_agent_tooling/tools/tokens/usd.py +79 -0
  43. prediction_market_agent_tooling/tools/utils.py +14 -8
  44. prediction_market_agent_tooling/tools/web3_utils.py +24 -41
  45. {prediction_market_agent_tooling-0.61.2.dev479.dist-info → prediction_market_agent_tooling-0.62.0.dist-info}/METADATA +2 -1
  46. {prediction_market_agent_tooling-0.61.2.dev479.dist-info → prediction_market_agent_tooling-0.62.0.dist-info}/RECORD +49 -47
  47. prediction_market_agent_tooling/abis/gvp2_settlement.abi.json +0 -89
  48. {prediction_market_agent_tooling-0.61.2.dev479.dist-info → prediction_market_agent_tooling-0.62.0.dist-info}/LICENSE +0 -0
  49. {prediction_market_agent_tooling-0.61.2.dev479.dist-info → prediction_market_agent_tooling-0.62.0.dist-info}/WHEEL +0 -0
  50. {prediction_market_agent_tooling-0.61.2.dev479.dist-info → prediction_market_agent_tooling-0.62.0.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,3 @@
1
- import sys
2
1
  import typing as t
3
2
  from datetime import timedelta
4
3
 
@@ -7,16 +6,17 @@ from web3 import Web3
7
6
 
8
7
  from prediction_market_agent_tooling.config import APIKeys
9
8
  from prediction_market_agent_tooling.gtypes import (
9
+ USD,
10
10
  ChecksumAddress,
11
+ CollateralToken,
11
12
  HexAddress,
12
13
  HexStr,
13
- OmenOutcomeToken,
14
14
  OutcomeStr,
15
+ OutcomeToken,
16
+ OutcomeWei,
15
17
  Probability,
16
18
  Wei,
17
- wei_type,
18
19
  xDai,
19
- xdai_type,
20
20
  )
21
21
  from prediction_market_agent_tooling.loggers import logger
22
22
  from prediction_market_agent_tooling.markets.agent_market import (
@@ -27,17 +27,11 @@ from prediction_market_agent_tooling.markets.agent_market import (
27
27
  ProcessedTradedMarket,
28
28
  SortBy,
29
29
  )
30
- from prediction_market_agent_tooling.markets.blockchain_utils import (
31
- get_total_balance,
32
- store_trades,
33
- )
30
+ from prediction_market_agent_tooling.markets.blockchain_utils import store_trades
34
31
  from prediction_market_agent_tooling.markets.data_models import (
35
32
  Bet,
36
- BetAmount,
37
- Currency,
38
- Position,
33
+ ExistingPosition,
39
34
  ResolvedBet,
40
- TokenAmount,
41
35
  )
42
36
  from prediction_market_agent_tooling.markets.omen.data_models import (
43
37
  OMEN_FALSE_OUTCOME,
@@ -65,6 +59,7 @@ from prediction_market_agent_tooling.markets.omen.omen_contracts import (
65
59
  build_parent_collection_id,
66
60
  )
67
61
  from prediction_market_agent_tooling.markets.omen.omen_subgraph_handler import (
62
+ SAFE_COLLATERAL_TOKENS_ADDRESSES,
68
63
  OmenSubgraphHandler,
69
64
  )
70
65
  from prediction_market_agent_tooling.tools.balances import get_balances
@@ -81,21 +76,20 @@ from prediction_market_agent_tooling.tools.tokens.auto_withdraw import (
81
76
  auto_withdraw_collateral_token,
82
77
  )
83
78
  from prediction_market_agent_tooling.tools.tokens.main_token import KEEPING_ERC20_TOKEN
79
+ from prediction_market_agent_tooling.tools.tokens.usd import (
80
+ get_token_in_usd,
81
+ get_usd_in_token,
82
+ get_xdai_in_usd,
83
+ )
84
84
  from prediction_market_agent_tooling.tools.utils import (
85
85
  DatetimeUTC,
86
86
  calculate_sell_amount_in_collateral,
87
87
  check_not_none,
88
88
  )
89
- from prediction_market_agent_tooling.tools.web3_utils import (
90
- add_fraction,
91
- get_receipt_block_timestamp,
92
- remove_fraction,
93
- wei_to_xdai,
94
- xdai_to_wei,
95
- )
89
+ from prediction_market_agent_tooling.tools.web3_utils import get_receipt_block_timestamp
96
90
 
97
- OMEN_DEFAULT_REALITIO_BOND_VALUE = xdai_type(0.01)
98
- OMEN_TINY_BET_AMOUNT = xdai_type(0.00001)
91
+ OMEN_DEFAULT_REALITIO_BOND_VALUE = xDai(0.01)
92
+ OMEN_TINY_BET_AMOUNT = USD(0.00001)
99
93
 
100
94
 
101
95
  class OmenAgentMarket(AgentMarket):
@@ -103,7 +97,6 @@ class OmenAgentMarket(AgentMarket):
103
97
  Omen's market class that can be used by agents to make predictions.
104
98
  """
105
99
 
106
- currency: t.ClassVar[Currency] = Currency.xDai
107
100
  base_url: t.ClassVar[str] = PRESAGIO_BASE_URL
108
101
  creator: HexAddress
109
102
 
@@ -152,25 +145,24 @@ class OmenAgentMarket(AgentMarket):
152
145
  def get_liquidity_in_wei(self, web3: Web3 | None = None) -> Wei:
153
146
  return self.get_contract().totalSupply(web3)
154
147
 
155
- def get_liquidity_in_xdai(self, web3: Web3 | None = None) -> xDai:
156
- return wei_to_xdai(self.get_liquidity_in_wei(web3))
148
+ def get_liquidity(self, web3: Web3 | None = None) -> CollateralToken:
149
+ return self.get_liquidity_in_wei(web3).as_token
157
150
 
158
- def get_liquidity(self) -> TokenAmount:
159
- return TokenAmount(
160
- amount=self.get_liquidity_in_xdai(),
161
- currency=self.currency,
162
- )
151
+ def get_tiny_bet_amount(self) -> CollateralToken:
152
+ return self.get_in_token(OMEN_TINY_BET_AMOUNT)
163
153
 
164
- @classmethod
165
- def get_tiny_bet_amount(cls) -> BetAmount:
166
- return BetAmount(amount=OMEN_TINY_BET_AMOUNT, currency=cls.currency)
154
+ def get_token_in_usd(self, x: CollateralToken) -> USD:
155
+ return get_token_in_usd(x, self.collateral_token_contract_address_checksummed)
156
+
157
+ def get_usd_in_token(self, x: USD) -> CollateralToken:
158
+ return get_usd_in_token(x, self.collateral_token_contract_address_checksummed)
167
159
 
168
160
  def liquidate_existing_positions(
169
161
  self,
170
162
  bet_outcome: bool,
171
163
  web3: Web3 | None = None,
172
164
  api_keys: APIKeys | None = None,
173
- larger_than: float | None = None,
165
+ larger_than: OutcomeToken | None = None,
174
166
  ) -> None:
175
167
  """
176
168
  Liquidates all previously existing positions.
@@ -179,16 +171,14 @@ class OmenAgentMarket(AgentMarket):
179
171
  api_keys = api_keys if api_keys is not None else APIKeys()
180
172
  better_address = api_keys.bet_from_address
181
173
  larger_than = (
182
- larger_than
183
- if larger_than is not None
184
- else self.get_liquidatable_amount().amount
174
+ larger_than if larger_than is not None else self.get_liquidatable_amount()
185
175
  )
186
176
  prev_positions_for_market = self.get_positions(
187
177
  user_id=better_address, liquid_only=True, larger_than=larger_than
188
178
  )
189
179
 
190
180
  for prev_position in prev_positions_for_market:
191
- for position_outcome, token_amount in prev_position.amounts.items():
181
+ for position_outcome, token_amount in prev_position.amounts_ot.items():
192
182
  position_outcome_bool = get_boolean_outcome(position_outcome)
193
183
  if position_outcome_bool != bet_outcome:
194
184
  self.sell_tokens(
@@ -202,7 +192,7 @@ class OmenAgentMarket(AgentMarket):
202
192
  def place_bet(
203
193
  self,
204
194
  outcome: bool,
205
- amount: BetAmount,
195
+ amount: USD,
206
196
  auto_deposit: bool = True,
207
197
  web3: Web3 | None = None,
208
198
  api_keys: APIKeys | None = None,
@@ -211,12 +201,9 @@ class OmenAgentMarket(AgentMarket):
211
201
  raise ValueError(
212
202
  f"Market {self.id} is not open for trading. Cannot place bet."
213
203
  )
214
- if amount.currency != self.currency:
215
- raise ValueError(f"Omen bets are made in xDai. Got {amount.currency}.")
216
- amount_xdai = xDai(amount.amount)
217
204
  return binary_omen_buy_outcome_tx(
218
205
  api_keys=api_keys if api_keys is not None else APIKeys(),
219
- amount=amount_xdai,
206
+ amount=amount,
220
207
  market=self,
221
208
  binary_outcome=outcome,
222
209
  auto_deposit=auto_deposit,
@@ -226,7 +213,7 @@ class OmenAgentMarket(AgentMarket):
226
213
  def buy_tokens(
227
214
  self,
228
215
  outcome: bool,
229
- amount: TokenAmount,
216
+ amount: USD,
230
217
  web3: Web3 | None = None,
231
218
  api_keys: APIKeys | None = None,
232
219
  ) -> str:
@@ -237,28 +224,37 @@ class OmenAgentMarket(AgentMarket):
237
224
  api_keys=api_keys,
238
225
  )
239
226
 
240
- def calculate_sell_amount_in_collateral(
241
- self, amount: TokenAmount, outcome: bool, web3: Web3 | None = None
242
- ) -> xDai:
227
+ def get_sell_value_of_outcome_token(
228
+ self, outcome: str, amount: OutcomeToken, web3: Web3 | None = None
229
+ ) -> CollateralToken:
230
+ """
231
+ Market can have as collateral token GNO for example.
232
+ When you place bet, you buy shares with GNO. For example, you get 10 shares for 1 GNO.
233
+ When selling, you need to provide the amount in GNO, which is cumbersome because you know how much shares you have, but you don't have the price of the shares in GNO.
234
+ Use this to convert how much collateral token (GNO in our example) to sell, to get the amount of shares you want to sell.
235
+ """
236
+ outcome_bool = get_boolean_outcome(outcome)
237
+
243
238
  pool_balance = get_conditional_tokens_balance_for_market(
244
239
  self, self.market_maker_contract_address_checksummed, web3=web3
245
240
  )
246
241
 
247
- sell_str = self.outcomes[self.yes_index if outcome else self.no_index]
248
- other_str = self.outcomes[self.no_index if outcome else self.yes_index]
242
+ sell_str = self.outcomes[self.yes_index if outcome_bool else self.no_index]
243
+ other_str = self.outcomes[self.no_index if outcome_bool else self.yes_index]
249
244
 
250
245
  collateral = calculate_sell_amount_in_collateral(
251
- shares_to_sell=amount.amount,
252
- holdings=wei_to_xdai(pool_balance[self.get_index_set(sell_str)]),
253
- other_holdings=wei_to_xdai(pool_balance[self.get_index_set(other_str)]),
246
+ shares_to_sell=amount,
247
+ holdings=pool_balance[self.get_index_set(sell_str)].as_outcome_token,
248
+ other_holdings=pool_balance[self.get_index_set(other_str)].as_outcome_token,
254
249
  fees=self.fees,
255
250
  )
256
- return xDai(collateral)
251
+
252
+ return collateral
257
253
 
258
254
  def sell_tokens(
259
255
  self,
260
256
  outcome: bool,
261
- amount: TokenAmount,
257
+ amount: USD | OutcomeToken,
262
258
  auto_withdraw: bool = True,
263
259
  api_keys: APIKeys | None = None,
264
260
  web3: Web3 | None = None,
@@ -267,16 +263,8 @@ class OmenAgentMarket(AgentMarket):
267
263
  raise ValueError(
268
264
  f"Market {self.id} is not open for trading. Cannot sell tokens."
269
265
  )
270
-
271
- # Convert from token (i.e. share) number to xDai value of tokens, as
272
- # this is the expected unit of the argument in the smart contract.
273
- collateral = self.calculate_sell_amount_in_collateral(
274
- amount=amount,
275
- outcome=outcome,
276
- web3=web3,
277
- )
278
266
  return binary_omen_sell_outcome_tx(
279
- amount=collateral,
267
+ amount=amount,
280
268
  api_keys=api_keys if api_keys is not None else APIKeys(),
281
269
  market=self,
282
270
  binary_outcome=outcome,
@@ -324,7 +312,7 @@ class OmenAgentMarket(AgentMarket):
324
312
  better_address=user,
325
313
  position_id_in=[p.id for p in positions],
326
314
  # After redeem, this will became zero.
327
- total_balance_bigger_than=wei_type(0),
315
+ total_balance_bigger_than=OutcomeWei(0),
328
316
  )
329
317
  return len(user_positions) > 0
330
318
 
@@ -361,16 +349,16 @@ class OmenAgentMarket(AgentMarket):
361
349
  current_p_yes=model.current_p_yes,
362
350
  condition=model.condition,
363
351
  url=model.url,
364
- volume=wei_to_xdai(model.collateralVolume),
352
+ volume=model.collateralVolume.as_token,
365
353
  close_time=model.close_time,
366
354
  fees=MarketFees(
367
355
  bet_proportion=(
368
- float(wei_to_xdai(model.fee)) if model.fee is not None else 0.0
356
+ model.fee.as_token.value if model.fee is not None else 0.0
369
357
  ),
370
358
  absolute=0,
371
359
  ),
372
360
  outcome_token_pool={
373
- model.outcomes[i]: wei_to_xdai(Wei(model.outcomeTokenAmounts[i]))
361
+ model.outcomes[i]: model.outcomeTokenAmounts[i].as_outcome_token
374
362
  for i in range(len(model.outcomes))
375
363
  },
376
364
  )
@@ -407,22 +395,24 @@ class OmenAgentMarket(AgentMarket):
407
395
  redeem_from_all_user_positions(api_keys)
408
396
 
409
397
  @staticmethod
410
- def get_trade_balance(api_keys: APIKeys, web3: Web3 | None = None) -> xDai:
411
- native_token_balance = get_balances(api_keys.bet_from_address, web3=web3).xdai
412
- return xdai_type(
413
- wei_to_xdai(
414
- KEEPING_ERC20_TOKEN.balanceOf(api_keys.bet_from_address, web3=web3)
415
- )
416
- + native_token_balance
398
+ def get_trade_balance(api_keys: APIKeys, web3: Web3 | None = None) -> USD:
399
+ native_usd = get_xdai_in_usd(
400
+ get_balances(api_keys.bet_from_address, web3=web3).xdai
417
401
  )
402
+ keeping_usd = get_token_in_usd(
403
+ KEEPING_ERC20_TOKEN.balance_of_in_tokens(
404
+ api_keys.bet_from_address, web3=web3
405
+ ),
406
+ KEEPING_ERC20_TOKEN.address,
407
+ )
408
+ return keeping_usd + native_usd
418
409
 
419
410
  @staticmethod
420
411
  def verify_operational_balance(api_keys: APIKeys) -> bool:
421
- return get_total_balance(
422
- api_keys.public_key,
412
+ return get_balances(
423
413
  # Use `public_key`, not `bet_from_address` because transaction costs are paid from the EOA wallet.
424
- sum_wxdai=False,
425
- ) > xdai_type(0.001)
414
+ api_keys.public_key,
415
+ ).xdai > xDai(0.001)
426
416
 
427
417
  def store_prediction(
428
418
  self, processed_market: ProcessedMarket | None, keys: APIKeys, agent_name: str
@@ -497,22 +487,19 @@ class OmenAgentMarket(AgentMarket):
497
487
 
498
488
  def get_token_balance(
499
489
  self, user_id: str, outcome: str, web3: Web3 | None = None
500
- ) -> TokenAmount:
490
+ ) -> OutcomeToken:
501
491
  index_set = self.get_index_set(outcome)
502
492
  balances = get_conditional_tokens_balance_for_market(
503
493
  self, Web3.to_checksum_address(user_id), web3=web3
504
494
  )
505
- return TokenAmount(
506
- amount=wei_to_xdai(balances[index_set]),
507
- currency=self.currency,
508
- )
495
+ return balances[index_set].as_outcome_token
509
496
 
510
- def get_position(self, user_id: str) -> Position | None:
497
+ def get_position(self, user_id: str) -> ExistingPosition | None:
511
498
  liquidatable_amount = self.get_liquidatable_amount()
512
499
  existing_positions = self.get_positions(
513
500
  user_id=user_id,
514
501
  liquid_only=True,
515
- larger_than=liquidatable_amount.amount,
502
+ larger_than=liquidatable_amount,
516
503
  )
517
504
  existing_position = next(
518
505
  iter([i for i in existing_positions if i.market_id == self.id]), None
@@ -524,12 +511,12 @@ class OmenAgentMarket(AgentMarket):
524
511
  cls,
525
512
  user_id: str,
526
513
  liquid_only: bool = False,
527
- larger_than: float = 0,
528
- ) -> list[Position]:
514
+ larger_than: OutcomeToken = OutcomeToken(0),
515
+ ) -> t.Sequence[ExistingPosition]:
529
516
  sgh = OmenSubgraphHandler()
530
517
  omen_positions = sgh.get_user_positions(
531
518
  better_address=Web3.to_checksum_address(user_id),
532
- total_balance_bigger_than=xdai_to_wei(xDai(larger_than)),
519
+ total_balance_bigger_than=larger_than.as_outcome_wei,
533
520
  )
534
521
 
535
522
  # Sort positions and corresponding markets by condition_id
@@ -563,142 +550,105 @@ class OmenAgentMarket(AgentMarket):
563
550
  if liquid_only and not market.can_be_traded():
564
551
  continue
565
552
 
566
- amounts: dict[OutcomeStr, TokenAmount] = {}
553
+ amounts_ot: dict[OutcomeStr, OutcomeToken] = {}
554
+
567
555
  for omen_position in omen_positions:
568
556
  outecome_str = market.index_set_to_outcome_str(
569
557
  omen_position.position.index_set
570
558
  )
571
559
 
572
560
  # Validate that outcomes are unique for a given condition_id.
573
- if outecome_str in amounts:
561
+ if outecome_str in amounts_ot:
574
562
  raise ValueError(
575
- f"Outcome {outecome_str} already exists in {amounts=}"
563
+ f"Outcome {outecome_str} already exists in {amounts_ot=}"
576
564
  )
577
565
 
578
- amounts[outecome_str] = TokenAmount(
579
- amount=wei_to_xdai(omen_position.totalBalance),
580
- currency=cls.currency,
581
- )
582
-
583
- positions.append(Position(market_id=market.id, amounts=amounts))
584
-
585
- return positions
586
-
587
- @classmethod
588
- def get_positions_value(cls, positions: list[Position]) -> BetAmount:
589
- # Two dicts to map from market ids to (1) positions and (2) market.
590
- market_ids_positions = {p.market_id: p for p in positions}
591
- # Check there is only one position per market.
592
- if len(set(market_ids_positions.keys())) != len(positions):
593
- raise ValueError(
594
- f"Markets for positions ({market_ids_positions.keys()}) are not unique."
595
- )
596
- markets: list[OmenAgentMarket] = [
597
- OmenAgentMarket.from_data_model(m)
598
- for m in OmenSubgraphHandler().get_omen_binary_markets(
599
- limit=sys.maxsize, id_in=list(market_ids_positions.keys())
600
- )
601
- ]
602
- market_ids_markets = {m.id: m for m in markets}
566
+ amounts_ot[outecome_str] = omen_position.totalBalance.as_outcome_token
603
567
 
604
- # Validate that dict keys are the same.
605
- if set(market_ids_positions.keys()) != set(market_ids_markets.keys()):
606
- raise ValueError(
607
- f"Market ids in {market_ids_positions.keys()} are not the same as in {market_ids_markets.keys()}"
568
+ amounts_current = {
569
+ k: market.get_token_in_usd(
570
+ # If the market is not open for trading anymore, then current value is equal to potential value.
571
+ market.get_sell_value_of_outcome_token(k, v)
572
+ if market.can_be_traded()
573
+ else v.as_token
574
+ )
575
+ for k, v in amounts_ot.items()
576
+ }
577
+ amounts_potential = {
578
+ k: market.get_token_in_usd(v.as_token) for k, v in amounts_ot.items()
579
+ }
580
+ positions.append(
581
+ ExistingPosition(
582
+ market_id=market.id,
583
+ amounts_current=amounts_current,
584
+ amounts_potential=amounts_potential,
585
+ amounts_ot=amounts_ot,
586
+ )
608
587
  )
609
588
 
610
- # Initialise position value.
611
- total_position_value = 0.0
612
-
613
- for market_id in market_ids_positions.keys():
614
- position = market_ids_positions[market_id]
615
- market = market_ids_markets[market_id]
616
-
617
- yes_tokens = 0.0
618
- no_tokens = 0.0
619
- if OMEN_TRUE_OUTCOME in position.amounts:
620
- yes_tokens = position.amounts[OutcomeStr(OMEN_TRUE_OUTCOME)].amount
621
- if OMEN_FALSE_OUTCOME in position.amounts:
622
- no_tokens = position.amounts[OutcomeStr(OMEN_FALSE_OUTCOME)].amount
623
-
624
- # Account for the value of positions in resolved markets
625
- if market.is_resolved() and market.has_successful_resolution():
626
- valued_tokens = yes_tokens if market.boolean_outcome else no_tokens
627
- total_position_value += valued_tokens
628
-
629
- # Or if the market is open and trading, get the value of the position
630
- elif market.can_be_traded():
631
- total_position_value += yes_tokens * market.yes_outcome_price
632
- total_position_value += no_tokens * market.no_outcome_price
633
-
634
- # Or if the market is still open but not trading, estimate the value
635
- # of the position
636
- else:
637
- if yes_tokens:
638
- yes_price = check_not_none(
639
- market.get_last_trade_yes_outcome_price()
640
- )
641
- total_position_value += yes_tokens * yes_price
642
- if no_tokens:
643
- no_price = check_not_none(market.get_last_trade_no_outcome_price())
644
- total_position_value += no_tokens * no_price
645
-
646
- return BetAmount(amount=total_position_value, currency=cls.currency)
589
+ return positions
647
590
 
648
591
  @classmethod
649
592
  def get_user_url(cls, keys: APIKeys) -> str:
650
593
  return get_omen_user_url(keys.bet_from_address)
651
594
 
652
595
  def get_buy_token_amount(
653
- self, bet_amount: BetAmount, direction: bool
654
- ) -> TokenAmount:
596
+ self, bet_amount: USD | CollateralToken, direction: bool
597
+ ) -> OutcomeToken:
655
598
  """
656
599
  Note: this is only valid if the market instance's token pool is
657
600
  up-to-date with the smart contract.
658
601
  """
659
602
  outcome_token_pool = check_not_none(self.outcome_token_pool)
660
603
  amount = get_buy_outcome_token_amount(
661
- investment_amount=bet_amount.amount,
604
+ investment_amount=self.get_in_token(bet_amount),
662
605
  buy_direction=direction,
663
606
  yes_outcome_pool_size=outcome_token_pool[OMEN_TRUE_OUTCOME],
664
607
  no_outcome_pool_size=outcome_token_pool[OMEN_FALSE_OUTCOME],
665
608
  fees=self.fees,
666
609
  )
667
- return TokenAmount(amount=amount, currency=self.currency)
610
+ return amount
668
611
 
669
612
  def _get_buy_token_amount_from_smart_contract(
670
- self, bet_amount: BetAmount, direction: bool
671
- ) -> TokenAmount:
672
- received_token_amount_wei = Wei(
673
- self.get_contract().calcBuyAmount(
674
- investment_amount=xdai_to_wei(xDai(bet_amount.amount)),
675
- outcome_index=self.get_outcome_index(
676
- self.get_outcome_str_from_bool(direction)
677
- ),
678
- )
613
+ self, bet_amount: USD, direction: bool
614
+ ) -> OutcomeToken:
615
+ bet_amount_in_tokens = get_usd_in_token(
616
+ bet_amount, self.collateral_token_contract_address_checksummed
679
617
  )
680
- received_token_amount = float(wei_to_xdai(received_token_amount_wei))
681
- return TokenAmount(amount=received_token_amount, currency=self.currency)
618
+ received_token_amount_wei = self.get_contract().calcBuyAmount(
619
+ investment_amount=bet_amount_in_tokens.as_wei,
620
+ outcome_index=self.get_outcome_index(
621
+ self.get_outcome_str_from_bool(direction)
622
+ ),
623
+ )
624
+ received_token_amount = received_token_amount_wei.as_outcome_token
625
+ return received_token_amount
682
626
 
683
- def get_new_p_yes(self, bet_amount: BetAmount, direction: bool) -> Probability:
627
+ def get_new_p_yes(self, bet_amount: USD, direction: bool) -> Probability:
684
628
  """
685
629
  Calculate the new p_yes based on the bet amount and direction.
686
630
  """
687
631
  if not self.has_token_pool():
688
632
  raise ValueError("Outcome token pool is required to calculate new p_yes.")
689
633
 
634
+ bet_amount_in_tokens = self.get_usd_in_token(bet_amount)
690
635
  outcome_token_pool = check_not_none(self.outcome_token_pool)
691
- yes_outcome_pool_size = outcome_token_pool[self.get_outcome_str_from_bool(True)]
692
- no_outcome_pool_size = outcome_token_pool[self.get_outcome_str_from_bool(False)]
636
+
637
+ yes_outcome_pool_size = outcome_token_pool[
638
+ self.get_outcome_str_from_bool(True)
639
+ ].value
640
+ no_outcome_pool_size = outcome_token_pool[
641
+ self.get_outcome_str_from_bool(False)
642
+ ].value
693
643
 
694
644
  new_yes_outcome_pool_size = yes_outcome_pool_size + (
695
- self.fees.get_bet_size_after_fees(bet_amount.amount)
645
+ self.fees.get_after_fees(bet_amount_in_tokens).value
696
646
  )
697
647
  new_no_outcome_pool_size = no_outcome_pool_size + (
698
- self.fees.get_bet_size_after_fees(bet_amount.amount)
648
+ self.fees.get_after_fees(bet_amount_in_tokens).value
699
649
  )
700
650
 
701
- received_token_amount = self.get_buy_token_amount(bet_amount, direction).amount
651
+ received_token_amount = self.get_buy_token_amount(bet_amount, direction).value
702
652
  if direction:
703
653
  new_yes_outcome_pool_size -= received_token_amount
704
654
  else:
@@ -737,11 +687,18 @@ def get_omen_user_url(address: ChecksumAddress) -> str:
737
687
 
738
688
 
739
689
  def pick_binary_market(
740
- sort_by: SortBy = SortBy.CLOSING_SOONEST, filter_by: FilterBy = FilterBy.OPEN
690
+ sort_by: SortBy = SortBy.CLOSING_SOONEST,
691
+ filter_by: FilterBy = FilterBy.OPEN,
692
+ collateral_token_address_in: (
693
+ tuple[ChecksumAddress, ...] | None
694
+ ) = SAFE_COLLATERAL_TOKENS_ADDRESSES,
741
695
  ) -> OmenMarket:
742
696
  subgraph_handler = OmenSubgraphHandler()
743
697
  return subgraph_handler.get_omen_binary_markets_simple(
744
- limit=1, sort_by=sort_by, filter_by=filter_by
698
+ limit=1,
699
+ sort_by=sort_by,
700
+ filter_by=filter_by,
701
+ collateral_token_address_in=collateral_token_address_in,
745
702
  )[0]
746
703
 
747
704
 
@@ -752,7 +709,7 @@ def pick_binary_market(
752
709
  )
753
710
  def omen_buy_outcome_tx(
754
711
  api_keys: APIKeys,
755
- amount: xDai,
712
+ amount: USD | CollateralToken,
756
713
  market: OmenAgentMarket,
757
714
  outcome: str,
758
715
  auto_deposit: bool,
@@ -760,35 +717,36 @@ def omen_buy_outcome_tx(
760
717
  slippage: float = 0.01,
761
718
  ) -> str:
762
719
  """
763
- Bets the given amount of xDai for the given outcome in the given market.
720
+ Bets the given amount for the given outcome in the given market.
764
721
  """
765
- amount_wei = xdai_to_wei(amount)
766
-
767
722
  market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
768
723
  collateral_token_contract = market_contract.get_collateral_token_contract(web3)
769
724
 
770
- # In case of ERC4626, obtained (for example) sDai out of xDai could be lower than the `amount_wei`, so we need to handle it.
771
- amount_wei_to_buy = collateral_token_contract.get_in_shares(amount_wei, web3)
725
+ amount_token = market.get_in_token(amount)
726
+ amount_wei = amount_token.as_wei
727
+
728
+ logger.info(
729
+ f"Buying asked {amount.value=} {amount.symbol}, converted to {amount_token.value=} {amount_token.symbol} for {outcome=} in market {market.url=}."
730
+ )
772
731
 
773
732
  # Get the index of the outcome we want to buy.
774
733
  outcome_index: int = market.get_outcome_index(outcome)
775
734
 
776
735
  # Calculate the amount of shares we will get for the given investment amount.
777
736
  expected_shares = market_contract.calcBuyAmount(
778
- amount_wei_to_buy, outcome_index, web3=web3
737
+ amount_wei, outcome_index, web3=web3
779
738
  )
780
739
  # Allow small slippage.
781
- expected_shares = remove_fraction(expected_shares, slippage)
740
+ expected_shares = expected_shares.without_fraction(slippage)
782
741
  # Approve the market maker to withdraw our collateral token.
783
742
  collateral_token_contract.approve(
784
743
  api_keys=api_keys,
785
744
  for_address=market_contract.address,
786
- amount_wei=amount_wei_to_buy,
745
+ amount_wei=amount_wei,
787
746
  web3=web3,
788
747
  )
789
748
 
790
749
  if auto_deposit:
791
- # In auto-depositing, we need to deposit the original `amount_wei`, e.g. we can deposit 2 xDai, but receive 1.8 sDai, so for the bet we will use `amount_wei_to_buy`.
792
750
  auto_deposit_collateral_token(
793
751
  collateral_token_contract, amount_wei, api_keys, web3
794
752
  )
@@ -796,7 +754,7 @@ def omen_buy_outcome_tx(
796
754
  # Buy shares using the deposited xDai in the collateral token.
797
755
  tx_receipt = market_contract.buy(
798
756
  api_keys=api_keys,
799
- amount_wei=amount_wei_to_buy,
757
+ amount_wei=amount_wei,
800
758
  outcome_index=outcome_index,
801
759
  min_outcome_tokens_to_buy=expected_shares,
802
760
  web3=web3,
@@ -807,7 +765,7 @@ def omen_buy_outcome_tx(
807
765
 
808
766
  def binary_omen_buy_outcome_tx(
809
767
  api_keys: APIKeys,
810
- amount: xDai,
768
+ amount: USD | CollateralToken,
811
769
  market: OmenAgentMarket,
812
770
  binary_outcome: bool,
813
771
  auto_deposit: bool,
@@ -825,12 +783,12 @@ def binary_omen_buy_outcome_tx(
825
783
 
826
784
  def omen_sell_outcome_tx(
827
785
  api_keys: APIKeys,
828
- amount: xDai, # The xDai value of shares to sell.
786
+ amount: OutcomeToken | CollateralToken | USD,
829
787
  market: OmenAgentMarket,
830
788
  outcome: str,
831
789
  auto_withdraw: bool,
832
790
  web3: Web3 | None = None,
833
- slippage: float = 0.001,
791
+ slippage: float = 0.01,
834
792
  ) -> str:
835
793
  """
836
794
  Sells the given xDai value of shares corresponding to the given outcome in
@@ -839,13 +797,21 @@ def omen_sell_outcome_tx(
839
797
  The number of shares sold will depend on the share price at the time of the
840
798
  transaction.
841
799
  """
842
- amount_wei = xdai_to_wei(amount)
843
- amount_wei = remove_fraction(amount_wei, slippage)
844
-
845
800
  market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
846
801
  conditional_token_contract = OmenConditionalTokenContract()
847
802
  collateral_token_contract = market_contract.get_collateral_token_contract(web3)
848
803
 
804
+ amount_token = (
805
+ market.get_sell_value_of_outcome_token(outcome, amount, web3)
806
+ if isinstance(amount, OutcomeToken)
807
+ else market.get_in_token(amount)
808
+ )
809
+ amount_wei = amount_token.as_wei
810
+
811
+ logger.info(
812
+ f"Selling asked {amount.value=} {amount.symbol}, converted to {amount_wei.as_token.value=} {amount_wei.as_token.symbol} for {outcome=} in market {market.url=}."
813
+ )
814
+
849
815
  # Verify, that markets uses conditional tokens that we expect.
850
816
  if (
851
817
  market_contract.conditionalTokens(web3=web3)
@@ -855,15 +821,15 @@ def omen_sell_outcome_tx(
855
821
  f"Market {market.id} uses conditional token that we didn't expect, {market_contract.conditionalTokens()} != {conditional_token_contract.address=}"
856
822
  )
857
823
 
858
- # Get the index of the outcome we want to buy.
824
+ # Get the index of the outcome we want to sell.
859
825
  outcome_index: int = market.get_outcome_index(outcome)
860
826
 
861
- # Calculate the amount of shares we will sell for the given selling amount of xdai.
827
+ # Calculate the amount of shares we will sell for the given selling amount of collateral.
862
828
  max_outcome_tokens_to_sell = market_contract.calcSellAmount(
863
829
  amount_wei, outcome_index, web3=web3
864
830
  )
865
831
  # Allow small slippage.
866
- max_outcome_tokens_to_sell = add_fraction(max_outcome_tokens_to_sell, slippage)
832
+ max_outcome_tokens_to_sell = max_outcome_tokens_to_sell.with_fraction(slippage)
867
833
 
868
834
  # Approve the market maker to move our (all) conditional tokens.
869
835
  conditional_token_contract.setApprovalForAll(
@@ -893,7 +859,7 @@ def omen_sell_outcome_tx(
893
859
 
894
860
  def binary_omen_sell_outcome_tx(
895
861
  api_keys: APIKeys,
896
- amount: xDai,
862
+ amount: OutcomeToken | CollateralToken | USD,
897
863
  market: OmenAgentMarket,
898
864
  binary_outcome: bool,
899
865
  auto_withdraw: bool,
@@ -911,16 +877,16 @@ def binary_omen_sell_outcome_tx(
911
877
 
912
878
  def omen_create_market_tx(
913
879
  api_keys: APIKeys,
914
- initial_funds: xDai,
880
+ initial_funds: USD | CollateralToken,
915
881
  question: str,
916
882
  closing_time: DatetimeUTC,
917
883
  category: str,
918
884
  language: str,
919
- outcomes: list[str],
885
+ outcomes: t.Sequence[str],
920
886
  auto_deposit: bool,
921
887
  finalization_timeout: timedelta = REALITY_DEFAULT_FINALIZATION_TIMEOUT,
922
888
  fee_perc: float = OMEN_DEFAULT_MARKET_FEE_PERC,
923
- distribution_hint: list[OmenOutcomeToken] | None = None,
889
+ distribution_hint: list[OutcomeWei] | None = None,
924
890
  collateral_token_address: ChecksumAddress = WrappedxDaiContract().address,
925
891
  arbitrator: Arbitrator = Arbitrator.KLEROS_31_JURORS_WITH_APPEAL,
926
892
  web3: Web3 | None = None,
@@ -931,7 +897,12 @@ def omen_create_market_tx(
931
897
  web3 = (
932
898
  web3 or OmenFixedProductMarketMakerFactoryContract.get_web3()
933
899
  ) # Default to Gnosis web3.
934
- initial_funds_wei = xdai_to_wei(initial_funds)
900
+ initial_funds_in_collateral = (
901
+ get_usd_in_token(initial_funds, collateral_token_address)
902
+ if isinstance(initial_funds, USD)
903
+ else initial_funds
904
+ )
905
+ initial_funds_in_collateral_wei = initial_funds_in_collateral.as_wei
935
906
 
936
907
  realitio_contract = OmenRealitioContract()
937
908
  conditional_token_contract = OmenConditionalTokenContract()
@@ -955,9 +926,9 @@ def omen_create_market_tx(
955
926
 
956
927
  if auto_deposit:
957
928
  auto_deposit_collateral_token(
958
- collateral_token_contract=collateral_token_contract,
929
+ collateral_token_contract,
930
+ initial_funds_in_collateral_wei,
959
931
  api_keys=api_keys,
960
- amount_wei=initial_funds_wei,
961
932
  web3=web3,
962
933
  )
963
934
 
@@ -991,21 +962,16 @@ def omen_create_market_tx(
991
962
  web3=web3,
992
963
  )
993
964
 
994
- # In case of ERC4626, obtained (for example) sDai out of xDai could be lower than the `amount_wei`, so we need to handle it.
995
- initial_funds_in_shares = collateral_token_contract.get_in_shares(
996
- amount=initial_funds_wei, web3=web3
997
- )
998
-
999
965
  # Approve the market maker to withdraw our collateral token.
1000
966
  collateral_token_contract.approve(
1001
967
  api_keys=api_keys,
1002
968
  for_address=factory_contract.address,
1003
- amount_wei=initial_funds_in_shares,
969
+ amount_wei=initial_funds_in_collateral_wei,
1004
970
  web3=web3,
1005
971
  )
1006
972
 
1007
973
  # Create the market.
1008
- fee = xdai_to_wei(xdai_type(fee_perc))
974
+ fee = CollateralToken(fee_perc).as_wei
1009
975
  (
1010
976
  market_event,
1011
977
  funding_event,
@@ -1015,7 +981,7 @@ def omen_create_market_tx(
1015
981
  condition_id=condition_id,
1016
982
  fee=fee,
1017
983
  distribution_hint=distribution_hint,
1018
- initial_funds_wei=initial_funds_in_shares,
984
+ initial_funds_wei=initial_funds_in_collateral_wei,
1019
985
  collateral_token_address=collateral_token_contract.address,
1020
986
  web3=web3,
1021
987
  )
@@ -1032,7 +998,7 @@ def omen_create_market_tx(
1032
998
  condition_id=condition_id,
1033
999
  question_event=question_event,
1034
1000
  condition_event=cond_event,
1035
- initial_funds=initial_funds_wei,
1001
+ initial_funds=initial_funds_in_collateral_wei,
1036
1002
  fee=fee,
1037
1003
  distribution_hint=distribution_hint,
1038
1004
  )
@@ -1041,27 +1007,28 @@ def omen_create_market_tx(
1041
1007
  def omen_fund_market_tx(
1042
1008
  api_keys: APIKeys,
1043
1009
  market: OmenAgentMarket,
1044
- funds: Wei,
1010
+ funds: USD | CollateralToken,
1045
1011
  auto_deposit: bool,
1046
1012
  web3: Web3 | None = None,
1047
1013
  ) -> None:
1014
+ funds_in_collateral = market.get_in_token(funds)
1015
+ funds_in_collateral_wei = funds_in_collateral.as_wei
1048
1016
  market_contract = market.get_contract()
1049
1017
  collateral_token_contract = market_contract.get_collateral_token_contract(web3=web3)
1050
1018
 
1051
- amount_to_fund = collateral_token_contract.get_in_shares(funds, web3)
1052
-
1053
1019
  collateral_token_contract.approve(
1054
1020
  api_keys=api_keys,
1055
1021
  for_address=market_contract.address,
1056
- amount_wei=amount_to_fund,
1022
+ amount_wei=funds_in_collateral_wei,
1057
1023
  web3=web3,
1058
1024
  )
1059
1025
 
1060
1026
  if auto_deposit:
1061
- # In auto-depositing, we need to deposit the original `funds`, e.g. we can deposit 2 xDai, but receive 1.8 sDai, so for the funding we will use `amount_to_fund`.
1062
- auto_deposit_collateral_token(collateral_token_contract, funds, api_keys, web3)
1027
+ auto_deposit_collateral_token(
1028
+ collateral_token_contract, funds_in_collateral_wei, api_keys, web3
1029
+ )
1063
1030
 
1064
- market_contract.addFunding(api_keys, amount_to_fund, web3=web3)
1031
+ market_contract.addFunding(api_keys, funds_in_collateral_wei, web3=web3)
1065
1032
 
1066
1033
 
1067
1034
  def omen_redeem_full_position_tx(
@@ -1094,7 +1061,7 @@ def omen_redeem_full_position_tx(
1094
1061
  amount_per_index = get_conditional_tokens_balance_for_market(
1095
1062
  market, from_address, web3
1096
1063
  )
1097
- amount_wei = sum(amount_per_index.values())
1064
+ amount_wei = sum(amount_per_index.values(), start=OutcomeWei.zero())
1098
1065
  if amount_wei == 0:
1099
1066
  logger.debug("No balance to claim. Exiting.")
1100
1067
  return
@@ -1112,10 +1079,10 @@ def omen_redeem_full_position_tx(
1112
1079
  web3=web3,
1113
1080
  )
1114
1081
  new_balance = collateral_token_contract.balanceOf(from_address, web3=web3)
1115
- balance_diff = wei_type(new_balance - original_balance)
1082
+ balance_diff = new_balance - original_balance
1116
1083
 
1117
1084
  logger.info(
1118
- f"Redeemed {wei_to_xdai(balance_diff)} {collateral_token_contract.symbol_cached(web3=web3)} from market {market.question=} ({market.url})."
1085
+ f"Redeemed {balance_diff.as_token} {collateral_token_contract.symbol_cached(web3=web3)} from market {market.question=} ({market.url})."
1119
1086
  )
1120
1087
 
1121
1088
  if auto_withdraw:
@@ -1131,12 +1098,12 @@ def get_conditional_tokens_balance_for_market(
1131
1098
  market: OmenAgentMarket,
1132
1099
  from_address: ChecksumAddress,
1133
1100
  web3: Web3 | None = None,
1134
- ) -> dict[int, Wei]:
1101
+ ) -> dict[int, OutcomeWei]:
1135
1102
  """
1136
1103
  We derive the withdrawable balance from the ConditionalTokens contract through CollectionId -> PositionId (which
1137
1104
  also serves as tokenId) -> TokenBalances.
1138
1105
  """
1139
- balance_per_index_set: dict[int, Wei] = {}
1106
+ balance_per_index_set: dict[int, OutcomeWei] = {}
1140
1107
  conditional_token_contract = OmenConditionalTokenContract()
1141
1108
  parent_collection_id = build_parent_collection_id()
1142
1109
 
@@ -1153,7 +1120,7 @@ def get_conditional_tokens_balance_for_market(
1153
1120
  balance_for_position = conditional_token_contract.balanceOf(
1154
1121
  from_address=from_address, position_id=position_id, web3=web3
1155
1122
  )
1156
- balance_per_index_set[index_set] = wei_type(balance_for_position)
1123
+ balance_per_index_set[index_set] = balance_for_position
1157
1124
 
1158
1125
  return balance_per_index_set
1159
1126
 
@@ -1214,11 +1181,11 @@ def omen_remove_fund_market_tx(
1214
1181
  )
1215
1182
 
1216
1183
  new_balance = market_collateral_token_contract.balanceOf(from_address, web3=web3)
1217
- balance_diff = wei_type(new_balance - original_balance)
1184
+ balance_diff = new_balance - original_balance
1218
1185
 
1219
1186
  logger.debug(f"Result from merge positions {result}")
1220
1187
  logger.info(
1221
- f"Withdrawn {wei_to_xdai(balance_diff)} {market_collateral_token_contract.symbol_cached(web3=web3)} from liquidity at {market.url=}."
1188
+ f"Withdrawn {balance_diff.as_token} {market_collateral_token_contract.symbol_cached(web3=web3)} from liquidity at {market.url=}."
1222
1189
  )
1223
1190
 
1224
1191
  if auto_withdraw:
@@ -1244,7 +1211,7 @@ def redeem_from_all_user_positions(
1244
1211
  user_positions = OmenSubgraphHandler().get_user_positions(
1245
1212
  public_key,
1246
1213
  # After redeem, this will became zero and we won't re-process it.
1247
- total_balance_bigger_than=wei_type(0),
1214
+ total_balance_bigger_than=OutcomeWei(0),
1248
1215
  )
1249
1216
 
1250
1217
  for index, user_position in enumerate(user_positions):
@@ -1272,10 +1239,10 @@ def redeem_from_all_user_positions(
1272
1239
  web3=web3,
1273
1240
  )
1274
1241
  new_balance = collateral_token_contract.balanceOf(public_key, web3=web3)
1275
- balance_diff = wei_type(new_balance - original_balance)
1242
+ balance_diff = new_balance - original_balance
1276
1243
 
1277
1244
  logger.info(
1278
- f"Redeemed {wei_to_xdai(balance_diff)} {collateral_token_contract.symbol_cached(web3=web3)} from position {user_position.id=}."
1245
+ f"Redeemed {balance_diff.as_token} {collateral_token_contract.symbol_cached(web3=web3)} from position {user_position.id=}."
1279
1246
  )
1280
1247
 
1281
1248
  if auto_withdraw:
@@ -1346,23 +1313,21 @@ def send_keeping_token_to_eoa_xdai(
1346
1313
  )
1347
1314
  return
1348
1315
 
1349
- need_to_withdraw = xDai(
1350
- (min_required_balance - current_balances_eoa.xdai) * multiplier
1351
- )
1352
- need_to_withdraw_wei = xdai_to_wei(need_to_withdraw)
1316
+ need_to_withdraw = (min_required_balance - current_balances_eoa.xdai) * multiplier
1317
+ need_to_withdraw_wei = need_to_withdraw.as_xdai_wei
1353
1318
 
1354
- if current_balances_eoa.wxdai >= need_to_withdraw:
1319
+ if current_balances_eoa.wxdai >= need_to_withdraw.as_token:
1355
1320
  # If EOA has enough of wxDai, simply withdraw it.
1356
1321
  logger.info(
1357
1322
  f"Withdrawing {need_to_withdraw} wxDai from EOA to keep the EOA's xDai balance above the minimum required balance {min_required_balance}."
1358
1323
  )
1359
1324
  wxdai_contract.withdraw(
1360
1325
  api_keys=api_keys.copy_without_safe_address(),
1361
- amount_wei=need_to_withdraw_wei,
1326
+ amount_wei=need_to_withdraw_wei.as_wei,
1362
1327
  web3=web3,
1363
1328
  )
1364
1329
 
1365
- elif current_balances_betting.wxdai >= need_to_withdraw:
1330
+ elif current_balances_betting.wxdai >= need_to_withdraw.as_token:
1366
1331
  # If Safe has enough of wxDai:
1367
1332
  # First send them to EOA's address.
1368
1333
  logger.info(
@@ -1372,7 +1337,7 @@ def send_keeping_token_to_eoa_xdai(
1372
1337
  api_keys=api_keys,
1373
1338
  sender=api_keys.bet_from_address,
1374
1339
  recipient=api_keys.public_key,
1375
- amount_wei=need_to_withdraw_wei,
1340
+ amount_wei=need_to_withdraw_wei.as_wei,
1376
1341
  web3=web3,
1377
1342
  )
1378
1343
  # And then simply withdraw it.
@@ -1381,7 +1346,7 @@ def send_keeping_token_to_eoa_xdai(
1381
1346
  )
1382
1347
  wxdai_contract.withdraw(
1383
1348
  api_keys=api_keys.copy_without_safe_address(),
1384
- amount_wei=need_to_withdraw_wei,
1349
+ amount_wei=need_to_withdraw_wei.as_wei,
1385
1350
  web3=web3,
1386
1351
  )
1387
1352
 
@@ -1392,30 +1357,37 @@ def send_keeping_token_to_eoa_xdai(
1392
1357
 
1393
1358
 
1394
1359
  def get_buy_outcome_token_amount(
1395
- investment_amount: float,
1360
+ investment_amount: CollateralToken,
1396
1361
  buy_direction: bool,
1397
- yes_outcome_pool_size: float,
1398
- no_outcome_pool_size: float,
1362
+ yes_outcome_pool_size: OutcomeToken,
1363
+ no_outcome_pool_size: OutcomeToken,
1399
1364
  fees: MarketFees,
1400
- ) -> float:
1365
+ ) -> OutcomeToken:
1401
1366
  """
1402
1367
  Calculates the amount of outcome tokens received for a given investment
1403
1368
 
1404
1369
  Taken from https://github.com/gnosis/conditional-tokens-market-makers/blob/6814c0247c745680bb13298d4f0dd7f5b574d0db/contracts/FixedProductMarketMaker.sol#L264
1405
1370
  """
1406
- investment_amount_minus_fees = fees.get_bet_size_after_fees(investment_amount)
1371
+ investment_amount_minus_fees = fees.get_after_fees(investment_amount)
1372
+ investment_amount_minus_fees_as_ot = OutcomeToken(
1373
+ investment_amount_minus_fees.value
1374
+ )
1407
1375
  buy_token_pool_balance = (
1408
1376
  yes_outcome_pool_size if buy_direction else no_outcome_pool_size
1409
1377
  )
1410
1378
 
1411
1379
  pool_balance = no_outcome_pool_size if buy_direction else yes_outcome_pool_size
1412
- denominator = pool_balance + investment_amount_minus_fees
1413
- ending_outcome_balance = buy_token_pool_balance * pool_balance / denominator
1380
+ denominator = pool_balance + investment_amount_minus_fees_as_ot
1381
+ ending_outcome_balance = OutcomeToken(
1382
+ buy_token_pool_balance * pool_balance / denominator
1383
+ )
1414
1384
 
1415
1385
  if ending_outcome_balance <= 0:
1416
1386
  raise ValueError("must have non-zero balances")
1417
1387
 
1418
1388
  result = (
1419
- buy_token_pool_balance + investment_amount_minus_fees - ending_outcome_balance
1389
+ buy_token_pool_balance
1390
+ + investment_amount_minus_fees_as_ot
1391
+ - ending_outcome_balance
1420
1392
  )
1421
1393
  return result