prediction-market-agent-tooling 0.69.2__tar.gz → 0.69.4__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 (138) hide show
  1. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/PKG-INFO +1 -1
  2. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/deploy/agent.py +7 -1
  3. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/deploy/betting_strategy.py +10 -10
  4. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/deploy/constants.py +4 -0
  5. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/agent_market.py +3 -3
  6. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/data_models.py +2 -4
  7. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/omen/omen.py +20 -0
  8. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/seer/data_models.py +0 -7
  9. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/seer/price_manager.py +2 -4
  10. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/seer/seer.py +23 -16
  11. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/seer/seer_contracts.py +30 -6
  12. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/contract.py +25 -0
  13. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/cow/cow_order.py +1 -1
  14. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/cow/models.py +1 -0
  15. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/cow/semaphore.py +5 -2
  16. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/utils.py +46 -1
  17. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/web3_utils.py +36 -1
  18. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/pyproject.toml +3 -1
  19. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/LICENSE +0 -0
  20. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/README.md +0 -0
  21. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/agentresultmapping.abi.json +0 -0
  22. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/debuggingcontract.abi.json +0 -0
  23. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/depositablewrapper_erc20.abi.json +0 -0
  24. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/erc1155.abi.json +0 -0
  25. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
  26. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/erc4626.abi.json +0 -0
  27. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/erc721.abi.json +0 -0
  28. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/gvp2_settlement.abi.json +0 -0
  29. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
  30. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
  31. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
  32. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
  33. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
  34. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
  35. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
  36. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/omen_thumbnailmapping.abi.json +0 -0
  37. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/ownable.abi.json +0 -0
  38. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/ownable_erc721.abi.json +0 -0
  39. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/proxy.abi.json +0 -0
  40. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/seer_gnosis_router.abi.json +0 -0
  41. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/seer_market_factory.abi.json +0 -0
  42. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/abis/swapr_router.abi.json +0 -0
  43. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
  44. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
  45. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
  46. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/benchmark/utils.py +0 -0
  47. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/chains.py +0 -0
  48. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/config.py +0 -0
  49. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/data_download/langfuse_data_downloader.py +0 -0
  50. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
  51. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
  52. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
  53. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
  54. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/deploy/trade_interval.py +0 -0
  55. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/gtypes.py +0 -0
  56. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/jobs/__init__.py +0 -0
  57. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/jobs/jobs_models.py +0 -0
  58. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/jobs/omen/omen_jobs.py +0 -0
  59. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/loggers.py +0 -0
  60. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/logprobs_parser.py +0 -0
  61. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/base_subgraph_handler.py +0 -0
  62. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/blockchain_utils.py +0 -0
  63. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/categorize.py +0 -0
  64. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
  65. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
  66. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
  67. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/manifold/manifold.py +0 -0
  68. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
  69. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/market_fees.py +0 -0
  70. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/markets.py +0 -0
  71. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/metaculus/api.py +0 -0
  72. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/metaculus/data_models.py +0 -0
  73. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/metaculus/metaculus.py +0 -0
  74. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
  75. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/omen/cow_contracts.py +0 -0
  76. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/omen/data_models.py +0 -0
  77. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/omen/omen_constants.py +0 -0
  78. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +0 -0
  79. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +0 -0
  80. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +0 -0
  81. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
  82. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/polymarket/clob_manager.py +0 -0
  83. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/polymarket/constants.py +0 -0
  84. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
  85. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
  86. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/polymarket/polymarket_contracts.py +0 -0
  87. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/polymarket/polymarket_subgraph_handler.py +0 -0
  88. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
  89. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/seer/exceptions.py +0 -0
  90. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/seer/seer_api.py +0 -0
  91. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/seer/seer_subgraph_handler.py +0 -0
  92. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/seer/subgraph_data_models.py +0 -0
  93. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/markets/seer/swap_pool_handler.py +0 -0
  94. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/py.typed +0 -0
  95. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/_generic_value.py +0 -0
  96. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/balances.py +0 -0
  97. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
  98. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
  99. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/betting_strategies/utils.py +0 -0
  100. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/caches/db_cache.py +0 -0
  101. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/caches/inmemory_cache.py +0 -0
  102. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/caches/serializers.py +0 -0
  103. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/costs.py +0 -0
  104. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/custom_exceptions.py +0 -0
  105. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/datetime_utc.py +0 -0
  106. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/db/db_manager.py +0 -0
  107. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/google_utils.py +0 -0
  108. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
  109. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/httpx_cached_client.py +0 -0
  110. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/image_gen/image_gen.py +0 -0
  111. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/image_gen/market_thumbnail_gen.py +0 -0
  112. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/ipfs/ipfs_handler.py +0 -0
  113. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/is_invalid.py +0 -0
  114. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
  115. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/langfuse_.py +0 -0
  116. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/langfuse_client_utils.py +0 -0
  117. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/omen/reality_accuracy.py +0 -0
  118. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/omen/sell_positions.py +0 -0
  119. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
  120. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/perplexity/perplexity_client.py +0 -0
  121. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/perplexity/perplexity_models.py +0 -0
  122. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/perplexity/perplexity_search.py +0 -0
  123. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/relevant_news_analysis/data_models.py +0 -0
  124. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_analysis.py +0 -0
  125. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/relevant_news_analysis/relevant_news_cache.py +0 -0
  126. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/rephrase.py +0 -0
  127. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/safe.py +0 -0
  128. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/singleton.py +0 -0
  129. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/streamlit_user_login.py +0 -0
  130. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/tavily/tavily_models.py +0 -0
  131. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/tavily/tavily_search.py +0 -0
  132. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/tokens/auto_deposit.py +0 -0
  133. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/tokens/auto_withdraw.py +0 -0
  134. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/tokens/main_token.py +0 -0
  135. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/tokens/slippage.py +0 -0
  136. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/tokens/token_utils.py +0 -0
  137. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/tokens/usd.py +0 -0
  138. {prediction_market_agent_tooling-0.69.2 → prediction_market_agent_tooling-0.69.4}/prediction_market_agent_tooling/tools/transaction_cache.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: prediction-market-agent-tooling
3
- Version: 0.69.2
3
+ Version: 0.69.4
4
4
  Summary: Tools to benchmark, deploy and monitor prediction market agents.
5
5
  Author: Gnosis
6
6
  Requires-Python: >=3.10,<3.13
@@ -53,6 +53,7 @@ from prediction_market_agent_tooling.tools.tokens.main_token import (
53
53
  from prediction_market_agent_tooling.tools.utils import (
54
54
  DatetimeUTC,
55
55
  check_not_none,
56
+ retry_until_true,
56
57
  utcnow,
57
58
  )
58
59
 
@@ -645,8 +646,10 @@ class DeployableTraderAgent(DeployablePredictionAgent):
645
646
 
646
647
  total_amount = market.get_in_usd(market.get_tiny_bet_amount())
647
648
  existing_position = market.get_position(user_id=user_id)
649
+
648
650
  if existing_position and existing_position.total_amount_current > USD(0):
649
651
  total_amount += existing_position.total_amount_current
652
+
650
653
  return total_amount
651
654
 
652
655
  def get_betting_strategy(self, market: AgentMarket) -> BettingStrategy:
@@ -703,8 +706,11 @@ class DeployableTraderAgent(DeployablePredictionAgent):
703
706
  )
704
707
  case TradeType.SELL:
705
708
  # Get actual value of the position we are going to sell, and if it's less than we wanted to sell, simply sell all of it.
709
+ # In this palce, we expect to have positions, so retry a few times if None are returned, which sometimes happens due to flaky subgraph.
706
710
  current_position = check_not_none(
707
- market.get_position(
711
+ retry_until_true(
712
+ lambda x: x is not None and x.total_amount_ot > 0
713
+ )(market.get_position)(
708
714
  market.get_user_id(api_keys=self.api_keys)
709
715
  ),
710
716
  "Should exists if we are going to sell outcomes.",
@@ -5,9 +5,7 @@ import numpy as np
5
5
  from scipy.optimize import minimize_scalar
6
6
 
7
7
  from prediction_market_agent_tooling.benchmark.utils import get_most_probable_outcome
8
- from prediction_market_agent_tooling.deploy.constants import (
9
- INVALID_OUTCOME_LOWERCASE_IDENTIFIER,
10
- )
8
+ from prediction_market_agent_tooling.deploy.constants import is_invalid_outcome
11
9
  from prediction_market_agent_tooling.gtypes import (
12
10
  USD,
13
11
  CollateralToken,
@@ -302,7 +300,7 @@ class CategoricalMaxAccuracyBettingStrategy(BettingStrategy):
302
300
  ) -> OutcomeStr:
303
301
  # We get the first direction which is != direction.
304
302
  other_direction = [i for i in outcomes if i.lower() != direction.lower()][0]
305
- if INVALID_OUTCOME_LOWERCASE_IDENTIFIER in other_direction.lower():
303
+ if is_invalid_outcome(other_direction):
306
304
  raise ValueError("Invalid outcome found as opposite direction. Exitting.")
307
305
  return other_direction
308
306
 
@@ -459,7 +457,7 @@ class _BinaryKellyBettingStrategy(BettingStrategy):
459
457
  )
460
458
  # We get the first direction which is != direction.
461
459
  other_direction = [i for i in market.outcomes if i != direction][0]
462
- if INVALID_OUTCOME_LOWERCASE_IDENTIFIER in other_direction.lower():
460
+ if is_invalid_outcome(other_direction):
463
461
  raise ValueError("Invalid outcome found as opposite direction. Exitting.")
464
462
 
465
463
  kelly_bet = self.get_kelly_bet(
@@ -484,11 +482,13 @@ class _BinaryKellyBettingStrategy(BettingStrategy):
484
482
  bet_outcome = direction if kelly_bet.direction else other_direction
485
483
 
486
484
  amounts = {
487
- bet_outcome: BettingStrategy.cap_to_profitable_bet_amount(
488
- market, market.get_token_in_usd(kelly_bet_size), bet_outcome
489
- )
490
- if kelly_bet_size > 0
491
- else USD(0),
485
+ bet_outcome: (
486
+ BettingStrategy.cap_to_profitable_bet_amount(
487
+ market, market.get_token_in_usd(kelly_bet_size), bet_outcome
488
+ )
489
+ if kelly_bet_size > 0
490
+ else USD(0)
491
+ ),
492
492
  }
493
493
  target_position = Position(market_id=market.id, amounts_current=amounts)
494
494
  trades = self._build_rebalance_trades_from_positions(
@@ -7,3 +7,7 @@ YES_OUTCOME_LOWERCASE_IDENTIFIER = "yes"
7
7
  NO_OUTCOME_LOWERCASE_IDENTIFIER = "no"
8
8
  UP_OUTCOME_LOWERCASE_IDENTIFIER = "up"
9
9
  DOWN_OUTCOME_LOWERCASE_IDENTIFIER = "down"
10
+
11
+
12
+ def is_invalid_outcome(outcome: str) -> bool:
13
+ return INVALID_OUTCOME_LOWERCASE_IDENTIFIER in outcome.lower()
@@ -12,10 +12,10 @@ from prediction_market_agent_tooling.benchmark.utils import get_most_probable_ou
12
12
  from prediction_market_agent_tooling.config import APIKeys
13
13
  from prediction_market_agent_tooling.deploy.constants import (
14
14
  DOWN_OUTCOME_LOWERCASE_IDENTIFIER,
15
- INVALID_OUTCOME_LOWERCASE_IDENTIFIER,
16
15
  NO_OUTCOME_LOWERCASE_IDENTIFIER,
17
16
  UP_OUTCOME_LOWERCASE_IDENTIFIER,
18
17
  YES_OUTCOME_LOWERCASE_IDENTIFIER,
18
+ is_invalid_outcome,
19
19
  )
20
20
  from prediction_market_agent_tooling.gtypes import (
21
21
  OutcomeStr,
@@ -212,7 +212,7 @@ class AgentMarket(BaseModel):
212
212
 
213
213
  if len(lowercase_outcomes) == 3:
214
214
  invalid_outcome = lowercase_outcomes[-1]
215
- has_invalid = INVALID_OUTCOME_LOWERCASE_IDENTIFIER in invalid_outcome
215
+ has_invalid = is_invalid_outcome(invalid_outcome)
216
216
  return has_yes and has_no and has_invalid
217
217
 
218
218
  return has_yes and has_no
@@ -230,7 +230,7 @@ class AgentMarket(BaseModel):
230
230
 
231
231
  if len(lowercase_outcomes) == 3:
232
232
  invalid_outcome = lowercase_outcomes[-1]
233
- has_invalid = INVALID_OUTCOME_LOWERCASE_IDENTIFIER in invalid_outcome
233
+ has_invalid = is_invalid_outcome(invalid_outcome)
234
234
  return has_up and has_down and has_invalid
235
235
 
236
236
  return has_up and has_down
@@ -9,6 +9,7 @@ from prediction_market_agent_tooling.deploy.constants import (
9
9
  NO_OUTCOME_LOWERCASE_IDENTIFIER,
10
10
  UP_OUTCOME_LOWERCASE_IDENTIFIER,
11
11
  YES_OUTCOME_LOWERCASE_IDENTIFIER,
12
+ is_invalid_outcome,
12
13
  )
13
14
  from prediction_market_agent_tooling.gtypes import (
14
15
  USD,
@@ -224,10 +225,7 @@ class CategoricalProbabilisticAnswer(BaseModel):
224
225
  OutcomeStr(DOWN_OUTCOME_LOWERCASE_IDENTIFIER.upper())
225
226
  ] = answer.p_down
226
227
 
227
- if (
228
- market_outcomes
229
- and INVALID_OUTCOME_LOWERCASE_IDENTIFIER in lowercase_market_outcomes
230
- ):
228
+ if market_outcomes and any(is_invalid_outcome(o) for o in market_outcomes):
231
229
  probabilities[
232
230
  OutcomeStr(INVALID_OUTCOME_LOWERCASE_IDENTIFIER.capitalize())
233
231
  ] = Probability(1 - answer.p_up - answer.p_down)
@@ -704,6 +704,26 @@ def omen_buy_outcome_tx(
704
704
  auto_deposit: bool,
705
705
  web3: Web3 | None = None,
706
706
  slippage: float = 0.01,
707
+ ) -> str:
708
+ return omen_buy_outcome_tx_no_retry(
709
+ api_keys=api_keys,
710
+ amount=amount,
711
+ market=market,
712
+ outcome=outcome,
713
+ auto_deposit=auto_deposit,
714
+ web3=web3,
715
+ slippage=slippage,
716
+ )
717
+
718
+
719
+ def omen_buy_outcome_tx_no_retry(
720
+ api_keys: APIKeys,
721
+ amount: USD | CollateralToken,
722
+ market: OmenAgentMarket,
723
+ outcome: OutcomeStr,
724
+ auto_deposit: bool,
725
+ web3: Web3 | None = None,
726
+ slippage: float = 0.01,
707
727
  ) -> str:
708
728
  """
709
729
  Bets the given amount for the given outcome in the given market.
@@ -163,13 +163,6 @@ class SeerMarketWithQuestions(SeerMarket):
163
163
  questions: list[SeerMarketQuestions]
164
164
 
165
165
 
166
- class RedeemParams(BaseModel):
167
- model_config = ConfigDict(populate_by_name=True)
168
- market: ChecksumAddress
169
- outcome_indices: list[int] = Field(alias="outcomeIndexes")
170
- amounts: list[OutcomeWei]
171
-
172
-
173
166
  class ExactInputSingleParams(BaseModel):
174
167
  # from https://gnosisscan.io/address/0xffb643e73f280b97809a8b41f7232ab401a04ee1#code
175
168
  model_config = ConfigDict(populate_by_name=True)
@@ -2,9 +2,7 @@ from cachetools import TTLCache, cached
2
2
  from pydantic import BaseModel
3
3
  from web3 import Web3
4
4
 
5
- from prediction_market_agent_tooling.deploy.constants import (
6
- INVALID_OUTCOME_LOWERCASE_IDENTIFIER,
7
- )
5
+ from prediction_market_agent_tooling.deploy.constants import is_invalid_outcome
8
6
  from prediction_market_agent_tooling.gtypes import (
9
7
  ChecksumAddress,
10
8
  CollateralToken,
@@ -243,7 +241,7 @@ class PriceManager:
243
241
  f"Outcome {outcome} not found in outcome_token_pool for market {self.seer_market.url}."
244
242
  )
245
243
  if outcome not in probability_map:
246
- if INVALID_OUTCOME_LOWERCASE_IDENTIFIER not in outcome.lower():
244
+ if not is_invalid_outcome(outcome):
247
245
  raise PriceCalculationError(
248
246
  f"Couldn't get probability for {outcome} for market {self.seer_market.url}."
249
247
  )
@@ -49,7 +49,6 @@ from prediction_market_agent_tooling.markets.omen.omen_contracts import (
49
49
  SeerAgentResultMappingContract,
50
50
  )
51
51
  from prediction_market_agent_tooling.markets.seer.data_models import (
52
- RedeemParams,
53
52
  SeerMarket,
54
53
  SeerMarketWithQuestions,
55
54
  )
@@ -83,6 +82,7 @@ from prediction_market_agent_tooling.tools.cow.cow_order import (
83
82
  OrderStatusError,
84
83
  get_orders_by_owner,
85
84
  get_trades_by_order_uid,
85
+ handle_allowance,
86
86
  swap_tokens_waiting,
87
87
  wait_for_order_completion,
88
88
  )
@@ -234,7 +234,9 @@ class SeerAgentMarket(AgentMarket):
234
234
  def get_tiny_bet_amount(self) -> CollateralToken:
235
235
  return self.get_in_token(SEER_TINY_BET_AMOUNT)
236
236
 
237
- def get_position(self, user_id: str, web3: Web3 | None = None) -> ExistingPosition:
237
+ def get_position(
238
+ self, user_id: str, web3: Web3 | None = None
239
+ ) -> ExistingPosition | None:
238
240
  """
239
241
  Fetches position from the user in a given market.
240
242
  We ignore the INVALID balances since we are only interested in binary outcomes.
@@ -251,6 +253,10 @@ class SeerAgentMarket(AgentMarket):
251
253
 
252
254
  amounts_ot[outcome_str] = outcome_token_balance_wei.as_outcome_token
253
255
 
256
+ # Adhere to convenience from other markets, where we return None if user doesn't have any position.
257
+ if all(v == 0 for v in amounts_ot.values()):
258
+ return None
259
+
254
260
  amounts_current = {
255
261
  k: self.get_token_in_usd(self.get_sell_value_of_outcome_token(k, v))
256
262
  for k, v in amounts_ot.items()
@@ -273,6 +279,7 @@ class SeerAgentMarket(AgentMarket):
273
279
  """
274
280
  We filter the markets using previous trades by the user so that we don't have to process all Seer markets.
275
281
  """
282
+
276
283
  trades_by_user = get_seer_transactions(
277
284
  api_keys.bet_from_address, RPCConfig().CHAIN_ID
278
285
  )
@@ -293,10 +300,12 @@ class SeerAgentMarket(AgentMarket):
293
300
  return filtered_markets
294
301
 
295
302
  @staticmethod
296
- def redeem_winnings(api_keys: APIKeys) -> None:
297
- web3 = RPCConfig().get_web3()
303
+ def redeem_winnings(api_keys: APIKeys, web3: Web3 | None = None) -> None:
304
+ web3 = web3 or RPCConfig().get_web3()
298
305
  subgraph = SeerSubgraphHandler()
299
306
 
307
+ # ToDo - Find open positions by user directly
308
+
300
309
  closed_markets = subgraph.get_markets(
301
310
  filter_by=FilterBy.RESOLVED, sort_by=SortBy.NEWEST
302
311
  )
@@ -305,8 +314,8 @@ class SeerAgentMarket(AgentMarket):
305
314
  )
306
315
 
307
316
  market_balances = {
308
- market.id: market.get_outcome_token_balances(
309
- api_keys.bet_from_address, web3
317
+ market.id: list(
318
+ market.get_outcome_token_balances(api_keys.bet_from_address, web3)
310
319
  )
311
320
  for market in filtered_markets
312
321
  }
@@ -323,17 +332,15 @@ class SeerAgentMarket(AgentMarket):
323
332
  try:
324
333
  # GnosisRouter needs approval to use our outcome tokens
325
334
  for i, token in enumerate(market.wrapped_tokens):
326
- ContractERC20OnGnosisChain(
327
- address=Web3.to_checksum_address(token)
328
- ).approve(
329
- api_keys,
335
+ handle_allowance(
336
+ api_keys=api_keys,
337
+ sell_token=Web3.to_checksum_address(token),
338
+ amount_to_check_wei=market_balances[market.id][i].as_wei,
330
339
  for_address=gnosis_router.address,
331
- amount_wei=market_balances[market.id][i].as_wei,
332
340
  web3=web3,
333
341
  )
334
342
 
335
343
  # We can only ask for redeem of outcome tokens on correct outcomes
336
- # TODO: Implement more complex use-cases: https://github.com/gnosis/prediction-market-agent-tooling/issues/850
337
344
  amounts_to_redeem = [
338
345
  (amount if numerator > 0 else OutcomeWei(0))
339
346
  for amount, numerator in zip(
@@ -341,13 +348,13 @@ class SeerAgentMarket(AgentMarket):
341
348
  )
342
349
  ]
343
350
 
344
- # Redeem!
345
- params = RedeemParams(
351
+ gnosis_router.redeem_to_base(
352
+ api_keys,
346
353
  market=Web3.to_checksum_address(market.id),
347
- outcome_indices=list(range(len(market.payout_numerators))),
354
+ outcome_indexes=list(range(len(market.payout_numerators))),
348
355
  amounts=amounts_to_redeem,
356
+ web3=web3,
349
357
  )
350
- gnosis_router.redeem_to_base(api_keys, params=params, web3=web3)
351
358
  logger.info(f"Redeemed market {market.url}.")
352
359
  except Exception:
353
360
  logger.exception(
@@ -8,13 +8,13 @@ from prediction_market_agent_tooling.gtypes import (
8
8
  ABI,
9
9
  ChecksumAddress,
10
10
  OutcomeStr,
11
+ OutcomeWei,
11
12
  TxReceipt,
12
13
  Wei,
13
14
  xDai,
14
15
  )
15
16
  from prediction_market_agent_tooling.markets.seer.data_models import (
16
17
  ExactInputSingleParams,
17
- RedeemParams,
18
18
  )
19
19
  from prediction_market_agent_tooling.markets.seer.subgraph_data_models import (
20
20
  CreateCategoricalMarketsParams,
@@ -88,7 +88,7 @@ class SeerMarketFactory(ContractOnGnosisChain):
88
88
 
89
89
 
90
90
  class GnosisRouter(ContractOnGnosisChain):
91
- # https://gnosisscan.io/address/0x83183da839ce8228e31ae41222ead9edbb5cdcf1#code.
91
+ # https://gnosisscan.io/address/0xeC9048b59b3467415b1a38F63416407eA0c70fB8#code.
92
92
  abi: ABI = abi_field_validator(
93
93
  os.path.join(
94
94
  os.path.dirname(os.path.realpath(__file__)),
@@ -102,12 +102,18 @@ class GnosisRouter(ContractOnGnosisChain):
102
102
  def redeem_to_base(
103
103
  self,
104
104
  api_keys: APIKeys,
105
- params: RedeemParams,
105
+ market: ChecksumAddress,
106
+ outcome_indexes: list[int],
107
+ amounts: list[OutcomeWei],
106
108
  web3: Web3 | None = None,
107
109
  ) -> TxReceipt:
108
- params_dict = params.model_dump(by_alias=True)
109
110
  # We explicity set amounts since OutcomeWei gets serialized as dict
110
- params_dict["amounts"] = [amount.value for amount in params.amounts]
111
+ params_dict = {
112
+ "market": market,
113
+ "outcomeIndexes": outcome_indexes,
114
+ "amounts": [amount.value for amount in amounts],
115
+ }
116
+
111
117
  receipt_tx = self.send(
112
118
  api_keys=api_keys,
113
119
  function_name="redeemToBase",
@@ -116,6 +122,22 @@ class GnosisRouter(ContractOnGnosisChain):
116
122
  )
117
123
  return receipt_tx
118
124
 
125
+ def split_from_base(
126
+ self,
127
+ api_keys: APIKeys,
128
+ market_id: ChecksumAddress,
129
+ amount_wei: Wei,
130
+ web3: Web3 | None = None,
131
+ ) -> TxReceipt:
132
+ """Splits using xDAI and receives outcome tokens"""
133
+ return self.send_with_value(
134
+ api_keys=api_keys,
135
+ function_name="splitFromBase",
136
+ amount_wei=amount_wei,
137
+ function_params=[market_id],
138
+ web3=web3,
139
+ )
140
+
119
141
  def split_position(
120
142
  self,
121
143
  api_keys: APIKeys,
@@ -135,7 +157,6 @@ class GnosisRouter(ContractOnGnosisChain):
135
157
 
136
158
 
137
159
  class SwaprRouterContract(ContractOnGnosisChain):
138
- # File content taken from https://github.com/protofire/omen-exchange/blob/master/app/src/abi/marketMaker.json.
139
160
  abi: ABI = abi_field_validator(
140
161
  os.path.join(
141
162
  os.path.dirname(os.path.realpath(__file__)),
@@ -166,4 +187,7 @@ class SwaprRouterContract(ContractOnGnosisChain):
166
187
  function_name="exactInputSingle",
167
188
  function_params=[tuple(dict(params).values())],
168
189
  web3=web3,
190
+ # Use higher gas limit for complex swap operations to avoid slow estimation
191
+ # Typical Swapr swaps use 150k-300k gas, we set conservative
192
+ default_gas=400_000,
169
193
  )
@@ -116,6 +116,7 @@ class ContractBaseClass(BaseModel):
116
116
  tx_params: t.Optional[TxParams] = None,
117
117
  timeout: int = 180,
118
118
  web3: Web3 | None = None,
119
+ default_gas: int | None = None,
119
120
  ) -> TxReceipt:
120
121
  """
121
122
  Used for changing a state (writing) to the contract.
@@ -132,6 +133,7 @@ class ContractBaseClass(BaseModel):
132
133
  function_params=function_params,
133
134
  tx_params=tx_params,
134
135
  timeout=timeout,
136
+ default_gas=default_gas,
135
137
  )
136
138
  return send_function_on_contract_tx(
137
139
  web3=web3 or self.get_web3(),
@@ -142,6 +144,7 @@ class ContractBaseClass(BaseModel):
142
144
  function_params=function_params,
143
145
  tx_params=tx_params,
144
146
  timeout=timeout,
147
+ default_gas=default_gas,
145
148
  )
146
149
 
147
150
  def send_with_value(
@@ -431,6 +434,25 @@ class ContractWrapped1155BaseClass(ContractERC20BaseClass):
431
434
  )
432
435
  )
433
436
 
437
+ def factory(self, web3: Web3 | None = None) -> ChecksumAddress:
438
+ return Web3.to_checksum_address(self.call("factory", web3=web3))
439
+
440
+ def mint(
441
+ self,
442
+ api_keys: APIKeys,
443
+ to_address: ChecksumAddress,
444
+ amount: Wei,
445
+ tx_params: t.Optional[TxParams] = None,
446
+ web3: Web3 | None = None,
447
+ ) -> TxReceipt:
448
+ return self.send(
449
+ api_keys=api_keys,
450
+ function_name="mint",
451
+ function_params=[to_address, amount],
452
+ tx_params=tx_params,
453
+ web3=web3,
454
+ )
455
+
434
456
 
435
457
  class OwnableContract(ContractBaseClass):
436
458
  abi: ABI = abi_field_validator(
@@ -718,6 +740,9 @@ class ConditionalTokenContract(ContractBaseClass):
718
740
  .events.PayoutRedemption()
719
741
  .process_receipt(receipt_tx)
720
742
  )
743
+ logger.info(
744
+ f"Receipt tx: `{receipt_tx}` Redeem event logs: `{redeem_event_logs}`"
745
+ )
721
746
  redeem_event = PayoutRedemptionEvent(**redeem_event_logs[0]["args"])
722
747
  return redeem_event
723
748
 
@@ -191,7 +191,7 @@ def handle_allowance(
191
191
 
192
192
 
193
193
  @postgres_rate_limited(
194
- api_keys=APIKeys(), rate_id="swap_tokens_waiting", interval_seconds=60.0
194
+ api_keys=APIKeys(), rate_id="swap_tokens_waiting", interval_seconds=5.0
195
195
  )
196
196
  @tenacity.retry(
197
197
  reraise=True,
@@ -22,5 +22,6 @@ class Order(BaseModel):
22
22
 
23
23
  class RateLimit(SQLModel, table=True):
24
24
  __tablename__ = "rate_limit"
25
+ __table_args__ = {"extend_existing": True}
25
26
  id: str = Field(primary_key=True)
26
27
  last_called_at: DatetimeUTC = Field(default_factory=utcnow)
@@ -18,7 +18,10 @@ FALLBACK_SQL_ENGINE = "sqlite:///rate_limit.db"
18
18
 
19
19
 
20
20
  def postgres_rate_limited(
21
- api_keys: APIKeys, rate_id: str = "default", interval_seconds: float = 1.0
21
+ api_keys: APIKeys,
22
+ rate_id: str,
23
+ interval_seconds: float,
24
+ shared_db: bool = False,
22
25
  ) -> Callable[[F], F]:
23
26
  """rate_id is used to distinguish between different rate limits for different functions"""
24
27
  limiter = RateLimiter(id=rate_id, interval_seconds=interval_seconds)
@@ -28,7 +31,7 @@ def postgres_rate_limited(
28
31
  def wrapper(*args: Any, **kwargs: Any) -> Any:
29
32
  sqlalchemy_db_url = (
30
33
  api_keys.sqlalchemy_db_url.get_secret_value()
31
- if api_keys.SQLALCHEMY_DB_URL
34
+ if shared_db
32
35
  else FALLBACK_SQL_ENGINE
33
36
  )
34
37
 
@@ -1,8 +1,10 @@
1
+ import functools
1
2
  import os
2
3
  import subprocess
4
+ import time
3
5
  from datetime import datetime
4
6
  from math import prod
5
- from typing import Any, NoReturn, Optional, Type, TypeVar
7
+ from typing import Any, Callable, NoReturn, Optional, Type, TypeVar, cast
6
8
 
7
9
  import httpx
8
10
  import pytz
@@ -56,6 +58,49 @@ def check_not_none(
56
58
  return value
57
59
 
58
60
 
61
+ F = TypeVar("F", bound=Callable[..., Any])
62
+
63
+
64
+ def retry_until_true(
65
+ condition: Callable[[Any], bool],
66
+ max_retries: int = 3,
67
+ delay: float = 1.0,
68
+ ) -> Callable[[F], F]:
69
+ """
70
+ Decorator that retries a function if the condition on its result evaluates to False.
71
+
72
+ Args:
73
+ condition: Function that takes the result and returns True if acceptable, False to retry
74
+ max_retries: Maximum number of retry attempts
75
+ delay: Delay between retries in seconds
76
+ """
77
+
78
+ def decorator(func: F) -> F:
79
+ @functools.wraps(func)
80
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
81
+ for attempt in range(1, max_retries + 1):
82
+ result = func(*args, **kwargs)
83
+
84
+ if condition(result):
85
+ logger.info(f"Condition met for {func.__name__} on {attempt}.")
86
+ return result
87
+
88
+ if attempt < max_retries:
89
+ logger.debug(
90
+ f"Retry {attempt + 1}/{max_retries} for {func.__name__}"
91
+ )
92
+ time.sleep(delay)
93
+ else:
94
+ logger.warning(
95
+ f"All {max_retries} retries exhausted for {func.__name__}"
96
+ )
97
+ return result
98
+
99
+ return cast(F, wrapper)
100
+
101
+ return decorator
102
+
103
+
59
104
  def should_not_happen(
60
105
  msg: str = "Should not happen.", exp: Type[ValueError] = ValueError
61
106
  ) -> NoReturn:
@@ -1,4 +1,5 @@
1
1
  import binascii
2
+ import multiprocessing.context
2
3
  import secrets
3
4
  from typing import Any, Optional
4
5
 
@@ -7,12 +8,14 @@ import tenacity
7
8
  from eth_account import Account
8
9
  from eth_typing import URI
9
10
  from eth_utils.currency import MAX_WEI, MIN_WEI
11
+ from joblib import Parallel, delayed
10
12
  from pydantic.types import SecretStr
11
13
  from safe_eth.eth import EthereumClient
12
14
  from safe_eth.eth.ethereum_client import TxSpeed
13
15
  from safe_eth.safe.safe import SafeV141
14
16
  from web3 import Web3
15
17
  from web3.constants import HASH_ZERO
18
+ from web3.contract.contract import ContractFunction as Web3ContractFunction
16
19
  from web3.types import AccessList, AccessListEntry, Nonce, TxParams, TxReceipt
17
20
 
18
21
  from prediction_market_agent_tooling.gtypes import (
@@ -76,7 +79,7 @@ def unwrap_generic_value(value: Any) -> Any:
76
79
 
77
80
 
78
81
  def parse_function_params(
79
- params: Optional[list[Any] | tuple[Any] | dict[str, Any]]
82
+ params: Optional[list[Any] | tuple[Any] | dict[str, Any]],
80
83
  ) -> list[Any] | tuple[Any]:
81
84
  params = unwrap_generic_value(params)
82
85
  if params is None:
@@ -120,6 +123,7 @@ def prepare_tx(
120
123
  function_params: Optional[list[Any] | dict[str, Any]] = None,
121
124
  access_list: Optional[AccessList] = None,
122
125
  tx_params: Optional[TxParams] = None,
126
+ default_gas: int | None = None,
123
127
  ) -> TxParams:
124
128
  tx_params_new = _prepare_tx_params(web3, from_address, access_list, tx_params)
125
129
  contract = web3.eth.contract(address=contract_address, abi=contract_abi)
@@ -127,10 +131,37 @@ def prepare_tx(
127
131
  function_call = contract.functions[function_name](
128
132
  *parse_function_params(function_params)
129
133
  )
134
+ if default_gas is not None and "gas" not in tx_params_new:
135
+ tx_params_new["gas"] = estimate_gas_with_timeout(
136
+ function_call, default_gas=default_gas, tx_params=tx_params_new
137
+ )
130
138
  built_tx_params: TxParams = function_call.build_transaction(tx_params_new)
131
139
  return built_tx_params
132
140
 
133
141
 
142
+ def estimate_gas_with_timeout(
143
+ function_call: Web3ContractFunction,
144
+ default_gas: int,
145
+ timeout: int = 15,
146
+ tx_params: Optional[TxParams] = None,
147
+ ) -> int:
148
+ """
149
+ Tries to estimate the gas, but default to the default value on timeout.
150
+ """
151
+ try:
152
+ # We need n_jobs=-1, otherwise timeouting isn't applied.
153
+ result: list[int] = Parallel(n_jobs=-1, backend="threading", timeout=timeout)(
154
+ delayed(function_call.estimate_gas)(tx_params) for _ in range(1)
155
+ )
156
+ estimated_gas = result[0]
157
+ return int(estimated_gas * 1.2) # Add 20% buffer
158
+ except (TimeoutError, multiprocessing.context.TimeoutError):
159
+ logger.warning(
160
+ f"Gas estimation timed out after {timeout} seconds, using default: {default_gas}"
161
+ )
162
+ return default_gas
163
+
164
+
134
165
  def _prepare_tx_params(
135
166
  web3: Web3,
136
167
  from_address: ChecksumAddress | None,
@@ -182,6 +213,7 @@ def send_function_on_contract_tx(
182
213
  function_params: Optional[list[Any] | dict[str, Any]] = None,
183
214
  tx_params: Optional[TxParams] = None,
184
215
  timeout: int = 180,
216
+ default_gas: int | None = None,
185
217
  ) -> TxReceipt:
186
218
  public_key = private_key_to_public_key(from_private_key)
187
219
 
@@ -193,6 +225,7 @@ def send_function_on_contract_tx(
193
225
  function_name=function_name,
194
226
  function_params=function_params,
195
227
  tx_params=tx_params,
228
+ default_gas=default_gas,
196
229
  )
197
230
 
198
231
  receipt_tx = sign_send_and_get_receipt_tx(
@@ -221,6 +254,7 @@ def send_function_on_contract_tx_using_safe(
221
254
  function_params: Optional[list[Any] | dict[str, Any]] = None,
222
255
  tx_params: Optional[TxParams] = None,
223
256
  timeout: int = 180,
257
+ default_gas: int | None = None,
224
258
  ) -> TxReceipt:
225
259
  if not web3.provider.endpoint_uri: # type: ignore
226
260
  raise EnvironmentError("RPC_URL not available in web3 object.")
@@ -261,6 +295,7 @@ def send_function_on_contract_tx_using_safe(
261
295
  function_params=function_params,
262
296
  access_list=access_list,
263
297
  tx_params=tx_params,
298
+ default_gas=default_gas,
264
299
  )
265
300
  safe_tx = s.build_multisig_tx(
266
301
  to=Web3.to_checksum_address(tx_params["to"]),
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "prediction-market-agent-tooling"
3
- version = "0.69.2"
3
+ version = "0.69.4"
4
4
  description = "Tools to benchmark, deploy and monitor prediction market agents."
5
5
  authors = ["Gnosis"]
6
6
  readme = "README.md"
@@ -77,6 +77,8 @@ black = "^23.12.1"
77
77
  ape-foundry = "^0.8.2"
78
78
  eth-ape = "^0.8.34"
79
79
  diskcache = "^5.6.3"
80
+ freezegun = "^1.5.5"
81
+ pytest-line-profiler = "^0.2.1"
80
82
 
81
83
  [build-system]
82
84
  requires = ["poetry-core"]