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.
Files changed (30) hide show
  1. prediction_market_agent_tooling/abis/debuggingcontract.abi.json +29 -0
  2. prediction_market_agent_tooling/abis/omen_agentresultmapping.abi.json +171 -0
  3. prediction_market_agent_tooling/benchmark/benchmark.py +0 -93
  4. prediction_market_agent_tooling/config.py +16 -0
  5. prediction_market_agent_tooling/deploy/agent.py +86 -13
  6. prediction_market_agent_tooling/deploy/betting_strategy.py +5 -35
  7. prediction_market_agent_tooling/jobs/omen/omen_jobs.py +2 -1
  8. prediction_market_agent_tooling/markets/agent_market.py +14 -6
  9. prediction_market_agent_tooling/markets/data_models.py +14 -0
  10. prediction_market_agent_tooling/markets/manifold/api.py +3 -1
  11. prediction_market_agent_tooling/markets/manifold/manifold.py +7 -2
  12. prediction_market_agent_tooling/markets/metaculus/metaculus.py +6 -1
  13. prediction_market_agent_tooling/markets/omen/data_models.py +247 -6
  14. prediction_market_agent_tooling/markets/omen/omen.py +77 -43
  15. prediction_market_agent_tooling/markets/omen/omen_contracts.py +179 -33
  16. prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +35 -0
  17. prediction_market_agent_tooling/markets/polymarket/polymarket.py +1 -1
  18. prediction_market_agent_tooling/monitor/markets/polymarket.py +4 -0
  19. prediction_market_agent_tooling/monitor/monitor.py +3 -3
  20. prediction_market_agent_tooling/monitor/monitor_app.py +2 -2
  21. prediction_market_agent_tooling/tools/contract.py +50 -1
  22. prediction_market_agent_tooling/tools/ipfs/ipfs_handler.py +33 -0
  23. prediction_market_agent_tooling/tools/langfuse_client_utils.py +27 -12
  24. prediction_market_agent_tooling/tools/utils.py +28 -4
  25. prediction_market_agent_tooling/tools/web3_utils.py +7 -0
  26. {prediction_market_agent_tooling-0.48.18.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/METADATA +2 -1
  27. {prediction_market_agent_tooling-0.48.18.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/RECORD +30 -27
  28. {prediction_market_agent_tooling-0.48.18.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/LICENSE +0 -0
  29. {prediction_market_agent_tooling-0.48.18.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/WHEEL +0 -0
  30. {prediction_market_agent_tooling-0.48.18.dist-info → prediction_market_agent_tooling-0.49.1.dist-info}/entry_points.txt +0 -0
@@ -1,16 +1,16 @@
1
1
  import sys
2
2
  import typing as t
3
- from datetime import datetime
3
+ from datetime import datetime, timedelta
4
4
 
5
5
  import tenacity
6
6
  from web3 import Web3
7
- from web3.constants import HASH_ZERO
8
7
 
9
8
  from prediction_market_agent_tooling.config import APIKeys
10
9
  from prediction_market_agent_tooling.gtypes import (
11
10
  ChecksumAddress,
12
11
  HexAddress,
13
12
  HexStr,
13
+ OmenOutcomeToken,
14
14
  OutcomeStr,
15
15
  Probability,
16
16
  Wei,
@@ -37,6 +37,8 @@ from prediction_market_agent_tooling.markets.omen.data_models import (
37
37
  OMEN_TRUE_OUTCOME,
38
38
  PRESAGIO_BASE_URL,
39
39
  Condition,
40
+ ConditionPreparationEvent,
41
+ CreatedMarket,
40
42
  OmenBet,
41
43
  OmenMarket,
42
44
  OmenUserPosition,
@@ -44,7 +46,7 @@ from prediction_market_agent_tooling.markets.omen.data_models import (
44
46
  get_boolean_outcome,
45
47
  )
46
48
  from prediction_market_agent_tooling.markets.omen.omen_contracts import (
47
- OMEN_DEFAULT_MARKET_FEE,
49
+ OMEN_DEFAULT_MARKET_FEE_PERC,
48
50
  Arbitrator,
49
51
  OmenConditionalTokenContract,
50
52
  OmenFixedProductMarketMakerContract,
@@ -52,6 +54,7 @@ from prediction_market_agent_tooling.markets.omen.omen_contracts import (
52
54
  OmenOracleContract,
53
55
  OmenRealitioContract,
54
56
  WrappedxDaiContract,
57
+ build_parent_collection_id,
55
58
  )
56
59
  from prediction_market_agent_tooling.markets.omen.omen_subgraph_handler import (
57
60
  OmenSubgraphHandler,
@@ -71,6 +74,7 @@ from prediction_market_agent_tooling.tools.utils import (
71
74
  )
72
75
  from prediction_market_agent_tooling.tools.web3_utils import (
73
76
  add_fraction,
77
+ get_receipt_block_timestamp,
74
78
  remove_fraction,
75
79
  wei_to_xdai,
76
80
  xdai_to_wei,
@@ -189,7 +193,7 @@ class OmenAgentMarket(AgentMarket):
189
193
  omen_auto_deposit: bool = True,
190
194
  web3: Web3 | None = None,
191
195
  api_keys: APIKeys | None = None,
192
- ) -> None:
196
+ ) -> str:
193
197
  if not self.can_be_traded():
194
198
  raise ValueError(
195
199
  f"Market {self.id} is not open for trading. Cannot place bet."
@@ -197,7 +201,7 @@ class OmenAgentMarket(AgentMarket):
197
201
  if amount.currency != self.currency:
198
202
  raise ValueError(f"Omen bets are made in xDai. Got {amount.currency}.")
199
203
  amount_xdai = xDai(amount.amount)
200
- binary_omen_buy_outcome_tx(
204
+ return binary_omen_buy_outcome_tx(
201
205
  api_keys=api_keys if api_keys is not None else APIKeys(),
202
206
  amount=amount_xdai,
203
207
  market=self,
@@ -212,7 +216,7 @@ class OmenAgentMarket(AgentMarket):
212
216
  amount: TokenAmount,
213
217
  web3: Web3 | None = None,
214
218
  api_keys: APIKeys | None = None,
215
- ) -> None:
219
+ ) -> str:
216
220
  return self.place_bet(
217
221
  outcome=outcome,
218
222
  amount=amount,
@@ -245,7 +249,7 @@ class OmenAgentMarket(AgentMarket):
245
249
  auto_withdraw: bool = False,
246
250
  api_keys: APIKeys | None = None,
247
251
  web3: Web3 | None = None,
248
- ) -> None:
252
+ ) -> str:
249
253
  if not self.can_be_traded():
250
254
  raise ValueError(
251
255
  f"Market {self.id} is not open for trading. Cannot sell tokens."
@@ -258,7 +262,7 @@ class OmenAgentMarket(AgentMarket):
258
262
  outcome=outcome,
259
263
  web3=web3,
260
264
  )
261
- binary_omen_sell_outcome_tx(
265
+ return binary_omen_sell_outcome_tx(
262
266
  amount=collateral,
263
267
  api_keys=api_keys if api_keys is not None else APIKeys(),
264
268
  market=self,
@@ -325,6 +329,10 @@ class OmenAgentMarket(AgentMarket):
325
329
 
326
330
  omen_redeem_full_position_tx(api_keys=api_keys, market=self)
327
331
 
332
+ @staticmethod
333
+ def from_created_market(model: "CreatedMarket") -> "OmenAgentMarket":
334
+ return OmenAgentMarket.from_data_model(OmenMarket.from_created_market(model))
335
+
328
336
  @staticmethod
329
337
  def from_data_model(model: OmenMarket) -> "OmenAgentMarket":
330
338
  return OmenAgentMarket(
@@ -633,6 +641,14 @@ class OmenAgentMarket(AgentMarket):
633
641
  )
634
642
  return Probability(new_p_yes)
635
643
 
644
+ @staticmethod
645
+ def get_user_balance(user_id: str) -> float:
646
+ return float(get_balances(Web3.to_checksum_address(user_id)).total)
647
+
648
+ @staticmethod
649
+ def get_user_id(api_keys: APIKeys) -> str:
650
+ return api_keys.bet_from_address
651
+
636
652
 
637
653
  def get_omen_user_url(address: ChecksumAddress) -> str:
638
654
  return f"https://gnosisscan.io/address/{address}"
@@ -659,14 +675,14 @@ def omen_buy_outcome_tx(
659
675
  outcome: str,
660
676
  auto_deposit: bool,
661
677
  web3: Web3 | None = None,
662
- ) -> None:
678
+ ) -> str:
663
679
  """
664
680
  Bets the given amount of xDai for the given outcome in the given market.
665
681
  """
666
682
  amount_wei = xdai_to_wei(amount)
667
683
 
668
684
  market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
669
- collateral_token_contract = market_contract.get_collateral_token_contract()
685
+ collateral_token_contract = market_contract.get_collateral_token_contract(web3)
670
686
 
671
687
  # In case of ERC4626, obtained (for example) sDai out of xDai could be lower than the `amount_wei`, so we need to handle it.
672
688
  amount_wei_to_buy = collateral_token_contract.get_in_shares(amount_wei, web3)
@@ -695,7 +711,7 @@ def omen_buy_outcome_tx(
695
711
  )
696
712
 
697
713
  # Buy shares using the deposited xDai in the collateral token.
698
- market_contract.buy(
714
+ tx_receipt = market_contract.buy(
699
715
  api_keys=api_keys,
700
716
  amount_wei=amount_wei_to_buy,
701
717
  outcome_index=outcome_index,
@@ -703,6 +719,8 @@ def omen_buy_outcome_tx(
703
719
  web3=web3,
704
720
  )
705
721
 
722
+ return tx_receipt["transactionHash"].hex()
723
+
706
724
 
707
725
  def binary_omen_buy_outcome_tx(
708
726
  api_keys: APIKeys,
@@ -711,8 +729,8 @@ def binary_omen_buy_outcome_tx(
711
729
  binary_outcome: bool,
712
730
  auto_deposit: bool,
713
731
  web3: Web3 | None = None,
714
- ) -> None:
715
- omen_buy_outcome_tx(
732
+ ) -> str:
733
+ return omen_buy_outcome_tx(
716
734
  api_keys=api_keys,
717
735
  amount=amount,
718
736
  market=market,
@@ -729,7 +747,7 @@ def omen_sell_outcome_tx(
729
747
  outcome: str,
730
748
  auto_withdraw: bool,
731
749
  web3: Web3 | None = None,
732
- ) -> None:
750
+ ) -> str:
733
751
  """
734
752
  Sells the given xDai value of shares corresponding to the given outcome in
735
753
  the given market.
@@ -741,7 +759,7 @@ def omen_sell_outcome_tx(
741
759
 
742
760
  market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
743
761
  conditional_token_contract = OmenConditionalTokenContract()
744
- collateral_token_contract = market_contract.get_collateral_token_contract()
762
+ collateral_token_contract = market_contract.get_collateral_token_contract(web3)
745
763
 
746
764
  # Verify, that markets uses conditional tokens that we expect.
747
765
  if (
@@ -770,7 +788,7 @@ def omen_sell_outcome_tx(
770
788
  web3=web3,
771
789
  )
772
790
  # Sell the shares.
773
- market_contract.sell(
791
+ tx_receipt = market_contract.sell(
774
792
  api_keys,
775
793
  amount_wei,
776
794
  outcome_index,
@@ -792,6 +810,8 @@ def omen_sell_outcome_tx(
792
810
  web3,
793
811
  )
794
812
 
813
+ return tx_receipt["transactionHash"].hex()
814
+
795
815
 
796
816
  def binary_omen_sell_outcome_tx(
797
817
  api_keys: APIKeys,
@@ -800,8 +820,8 @@ def binary_omen_sell_outcome_tx(
800
820
  binary_outcome: bool,
801
821
  auto_withdraw: bool,
802
822
  web3: Web3 | None = None,
803
- ) -> None:
804
- omen_sell_outcome_tx(
823
+ ) -> str:
824
+ return omen_sell_outcome_tx(
805
825
  api_keys=api_keys,
806
826
  amount=amount,
807
827
  market=market,
@@ -820,10 +840,13 @@ def omen_create_market_tx(
820
840
  language: str,
821
841
  outcomes: list[str],
822
842
  auto_deposit: bool,
823
- fee: float = OMEN_DEFAULT_MARKET_FEE,
843
+ finalization_timeout: timedelta = timedelta(days=1),
844
+ fee_perc: float = OMEN_DEFAULT_MARKET_FEE_PERC,
845
+ distribution_hint: list[OmenOutcomeToken] | None = None,
824
846
  collateral_token_address: ChecksumAddress = WrappedxDaiContract().address,
847
+ arbitrator: Arbitrator = Arbitrator.KLEROS_31_JURORS_WITH_APPEAL,
825
848
  web3: Web3 | None = None,
826
- ) -> ChecksumAddress:
849
+ ) -> CreatedMarket:
827
850
  """
828
851
  Based on omen-exchange TypeScript code: https://github.com/protofire/omen-exchange/blob/b0b9a3e71b415d6becf21fe428e1c4fc0dad2e80/app/src/services/cpk/cpk.ts#L308
829
852
  """
@@ -861,28 +884,30 @@ def omen_create_market_tx(
861
884
  )
862
885
 
863
886
  # Create the question on Realitio.
864
- question_id = realitio_contract.askQuestion(
887
+ question_event = realitio_contract.askQuestion(
865
888
  api_keys=api_keys,
866
889
  question=question,
867
890
  category=category,
868
891
  outcomes=outcomes,
869
892
  language=language,
870
- arbitrator=Arbitrator.KLEROS,
893
+ arbitrator=arbitrator,
871
894
  opening=closing_time, # The question is opened at the closing time of the market.
895
+ timeout=finalization_timeout,
872
896
  web3=web3,
873
897
  )
874
898
 
875
899
  # Construct the condition id.
900
+ cond_event: ConditionPreparationEvent | None = None
876
901
  condition_id = conditional_token_contract.getConditionId(
877
- question_id=question_id,
902
+ question_id=question_event.question_id,
878
903
  oracle_address=oracle_contract.address,
879
904
  outcomes_slot_count=len(outcomes),
880
905
  web3=web3,
881
906
  )
882
907
  if not conditional_token_contract.does_condition_exists(condition_id, web3=web3):
883
- conditional_token_contract.prepareCondition(
908
+ cond_event = conditional_token_contract.prepareCondition(
884
909
  api_keys=api_keys,
885
- question_id=question_id,
910
+ question_id=question_event.question_id,
886
911
  oracle_address=oracle_contract.address,
887
912
  outcomes_slot_count=len(outcomes),
888
913
  web3=web3,
@@ -902,10 +927,16 @@ def omen_create_market_tx(
902
927
  )
903
928
 
904
929
  # Create the market.
905
- create_market_receipt_tx = factory_contract.create2FixedProductMarketMaker(
930
+ fee = xdai_to_wei(xdai_type(fee_perc))
931
+ (
932
+ market_event,
933
+ funding_event,
934
+ receipt_tx,
935
+ ) = factory_contract.create2FixedProductMarketMaker(
906
936
  api_keys=api_keys,
907
937
  condition_id=condition_id,
908
938
  fee=fee,
939
+ distribution_hint=distribution_hint,
909
940
  initial_funds_wei=initial_funds_in_shares,
910
941
  collateral_token_address=collateral_token_contract.address,
911
942
  web3=web3,
@@ -916,10 +947,17 @@ def omen_create_market_tx(
916
947
  # but address of stakingRewardsFactoryAddress on xDai/Gnosis is 0x0000000000000000000000000000000000000000,
917
948
  # so skipping it here.
918
949
 
919
- market_address = create_market_receipt_tx["logs"][-1][
920
- "address"
921
- ] # The market address is available in the last emitted log, in the address field.
922
- return market_address
950
+ return CreatedMarket(
951
+ market_creation_timestamp=get_receipt_block_timestamp(receipt_tx, web3),
952
+ market_event=market_event,
953
+ funding_event=funding_event,
954
+ condition_id=condition_id,
955
+ question_event=question_event,
956
+ condition_event=cond_event,
957
+ initial_funds=initial_funds_wei,
958
+ fee=fee,
959
+ distribution_hint=distribution_hint,
960
+ )
923
961
 
924
962
 
925
963
  def omen_fund_market_tx(
@@ -930,7 +968,7 @@ def omen_fund_market_tx(
930
968
  web3: Web3 | None = None,
931
969
  ) -> None:
932
970
  market_contract = market.get_contract()
933
- collateral_token_contract = market_contract.get_collateral_token_contract()
971
+ collateral_token_contract = market_contract.get_collateral_token_contract(web3=web3)
934
972
 
935
973
  amount_to_fund = collateral_token_contract.get_in_shares(funds, web3)
936
974
 
@@ -948,10 +986,6 @@ def omen_fund_market_tx(
948
986
  market_contract.addFunding(api_keys, amount_to_fund, web3=web3)
949
987
 
950
988
 
951
- def build_parent_collection_id() -> HexStr:
952
- return HASH_ZERO # Taken from Olas
953
-
954
-
955
989
  def omen_redeem_full_position_tx(
956
990
  api_keys: APIKeys,
957
991
  market: OmenAgentMarket,
@@ -973,8 +1007,6 @@ def omen_redeem_full_position_tx(
973
1007
  f"Market {market.id} uses conditional token that we didn't expect, {market_contract.conditionalTokens()} != {conditional_token_contract.address=}"
974
1008
  )
975
1009
 
976
- parent_collection_id = build_parent_collection_id()
977
-
978
1010
  if not market.is_resolved():
979
1011
  logger.debug("Cannot redeem winnings if market is not yet resolved. Exiting.")
980
1012
  return
@@ -995,7 +1027,6 @@ def omen_redeem_full_position_tx(
995
1027
  api_keys=api_keys,
996
1028
  collateral_token_address=market.collateral_token_contract_address_checksummed,
997
1029
  condition_id=market.condition.id,
998
- parent_collection_id=parent_collection_id,
999
1030
  index_sets=market.condition.index_sets,
1000
1031
  web3=web3,
1001
1032
  )
@@ -1048,8 +1079,12 @@ def omen_remove_fund_market_tx(
1048
1079
  """
1049
1080
  from_address = api_keys.bet_from_address
1050
1081
  market_contract = market.get_contract()
1051
- market_collateral_token_contract = market_contract.get_collateral_token_contract()
1052
- original_balance = market_collateral_token_contract.balanceOf(from_address)
1082
+ market_collateral_token_contract = market_contract.get_collateral_token_contract(
1083
+ web3=web3
1084
+ )
1085
+ original_balance = market_collateral_token_contract.balanceOf(
1086
+ from_address, web3=web3
1087
+ )
1053
1088
 
1054
1089
  total_shares = market_contract.balanceOf(from_address, web3=web3)
1055
1090
  if total_shares == 0:
@@ -1084,11 +1119,11 @@ def omen_remove_fund_market_tx(
1084
1119
  web3=web3,
1085
1120
  )
1086
1121
 
1087
- new_balance = market_collateral_token_contract.balanceOf(from_address)
1122
+ new_balance = market_collateral_token_contract.balanceOf(from_address, web3=web3)
1088
1123
 
1089
1124
  logger.debug(f"Result from merge positions {result}")
1090
1125
  logger.info(
1091
- f"Withdrawn {new_balance - original_balance} {market_collateral_token_contract.symbol_cached()} from liquidity at {market.url=}."
1126
+ f"Withdrawn {new_balance - original_balance} {market_collateral_token_contract.symbol_cached(web3=web3)} from liquidity at {market.url=}."
1092
1127
  )
1093
1128
 
1094
1129
 
@@ -1126,7 +1161,6 @@ def redeem_from_all_user_positions(
1126
1161
  api_keys=api_keys,
1127
1162
  collateral_token_address=user_position.position.collateral_token_contract_address_checksummed,
1128
1163
  condition_id=condition_id,
1129
- parent_collection_id=build_parent_collection_id(),
1130
1164
  index_sets=user_position.position.indexSets,
1131
1165
  web3=web3,
1132
1166
  )