prediction-market-agent-tooling 0.26.0__tar.gz → 0.28.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/PKG-INFO +1 -1
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/config.py +12 -29
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/agent.py +2 -4
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/loggers.py +21 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/agent_market.py +18 -1
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/markets.py +2 -3
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/omen.py +63 -59
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +29 -31
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +15 -15
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +9 -9
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/markets/omen.py +3 -5
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/markets/polymarket.py +2 -3
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/contract.py +16 -16
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/pyproject.toml +1 -1
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/LICENSE +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/README.md +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/abis/wxdai.abi.json +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/benchmark/utils.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/constants.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/gtypes.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/categorize.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/data_models.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/manifold/manifold.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/data_models.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/polymarket/api.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/polymarket/data_models.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/markets/polymarket/utils.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/langfuse/langfuse_wrapper.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/markets/manifold.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/monitor.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/monitor_app.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/monitor/monitor_settings.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/py.typed +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/balances.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/cache.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/costs.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/gnosis_rpc.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/google.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/is_predictable.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/safe.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/singleton.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/utils.py +0 -0
- {prediction_market_agent_tooling-0.26.0 → prediction_market_agent_tooling-0.28.0}/prediction_market_agent_tooling/tools/web3_utils.py +0 -0
@@ -2,7 +2,6 @@ import typing as t
|
|
2
2
|
|
3
3
|
from gnosis.eth import EthereumClient
|
4
4
|
from gnosis.safe import Safe
|
5
|
-
from pydantic import BaseModel
|
6
5
|
from pydantic.types import SecretStr
|
7
6
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
8
7
|
|
@@ -58,6 +57,15 @@ class APIKeys(BaseSettings):
|
|
58
57
|
"BET_FROM_PRIVATE_KEY missing in the environment.",
|
59
58
|
)
|
60
59
|
|
60
|
+
@property
|
61
|
+
def bet_from_address(self) -> ChecksumAddress:
|
62
|
+
"""If the SAFE is available, we always route transactions via SAFE. Otherwise we use the EOA."""
|
63
|
+
return (
|
64
|
+
self.SAFE_ADDRESS
|
65
|
+
if self.SAFE_ADDRESS
|
66
|
+
else private_key_to_public_key(self.bet_from_private_key)
|
67
|
+
)
|
68
|
+
|
61
69
|
@property
|
62
70
|
def openai_api_key(self) -> SecretStr:
|
63
71
|
return check_not_none(
|
@@ -110,35 +118,10 @@ class APIKeys(BaseSettings):
|
|
110
118
|
if APIKeys.model_fields[k].annotation in SECRET_TYPES and v is not None
|
111
119
|
}
|
112
120
|
|
113
|
-
|
114
|
-
class PrivateCredentials(BaseModel):
|
115
|
-
private_key: PrivateKey
|
116
|
-
safe_address: ChecksumAddress | None
|
117
|
-
|
118
|
-
@property
|
119
|
-
def public_key(self) -> ChecksumAddress:
|
120
|
-
"""If the SAFE is available, we always route transactions via SAFE. Otherwise we use the EOA."""
|
121
|
-
return (
|
122
|
-
self.safe_address
|
123
|
-
if self.safe_address is not None
|
124
|
-
else private_key_to_public_key(self.private_key)
|
125
|
-
)
|
126
|
-
|
127
|
-
@property
|
128
|
-
def has_safe_address(self) -> bool:
|
129
|
-
return self.safe_address is not None
|
130
|
-
|
131
|
-
@staticmethod
|
132
|
-
def from_api_keys(api_keys: APIKeys) -> "PrivateCredentials":
|
133
|
-
return PrivateCredentials(
|
134
|
-
private_key=api_keys.bet_from_private_key,
|
135
|
-
safe_address=api_keys.SAFE_ADDRESS,
|
136
|
-
)
|
137
|
-
|
138
121
|
def check_if_is_safe_owner(self, ethereum_client: EthereumClient) -> bool:
|
139
|
-
if not self.
|
122
|
+
if not self.SAFE_ADDRESS:
|
140
123
|
raise ValueError("Cannot check ownership if safe_address is not defined.")
|
141
124
|
|
142
|
-
s = Safe(self.
|
143
|
-
public_key_from_signer = private_key_to_public_key(self.
|
125
|
+
s = Safe(self.SAFE_ADDRESS, ethereum_client) # type: ignore[abstract]
|
126
|
+
public_key_from_signer = private_key_to_public_key(self.bet_from_private_key)
|
144
127
|
return s.retrieve_is_owner(public_key_from_signer)
|
@@ -8,7 +8,7 @@ from datetime import datetime, timedelta
|
|
8
8
|
from pydantic import BaseModel, BeforeValidator
|
9
9
|
from typing_extensions import Annotated
|
10
10
|
|
11
|
-
from prediction_market_agent_tooling.config import APIKeys
|
11
|
+
from prediction_market_agent_tooling.config import APIKeys
|
12
12
|
from prediction_market_agent_tooling.deploy.constants import (
|
13
13
|
MARKET_TYPE_KEY,
|
14
14
|
REPOSITORY_KEY,
|
@@ -260,11 +260,9 @@ class DeployableTraderAgent(DeployableAgent):
|
|
260
260
|
"""
|
261
261
|
Executes actions that occur before bets are placed.
|
262
262
|
"""
|
263
|
-
private_credentials = PrivateCredentials.from_api_keys(APIKeys())
|
264
|
-
|
265
263
|
if market_type == MarketType.OMEN:
|
266
264
|
# Omen is specific, because the user (agent) needs to manually withdraw winnings from the market.
|
267
|
-
redeem_from_all_user_positions(
|
265
|
+
redeem_from_all_user_positions(APIKeys())
|
268
266
|
|
269
267
|
def process_bets(self, market_type: MarketType) -> None:
|
270
268
|
"""
|
@@ -1,5 +1,7 @@
|
|
1
|
+
import builtins
|
1
2
|
import logging
|
2
3
|
import sys
|
4
|
+
import typing as t
|
3
5
|
import warnings
|
4
6
|
from enum import Enum
|
5
7
|
|
@@ -35,9 +37,11 @@ def patch_logger() -> None:
|
|
35
37
|
format_loguru = GCP_LOG_LOGURU_FORMAT
|
36
38
|
format_logging = GCP_LOG_LOGGING_FORMAT
|
37
39
|
datefmt_logging = GCP_LOG_FORMAT_LOGGING_DATEFMT
|
40
|
+
print_logging = print_using_loguru_info
|
38
41
|
|
39
42
|
elif config.LOG_FORMAT == LogFormat.DEFAULT:
|
40
43
|
format_loguru, format_logging, datefmt_logging = None, None, None
|
44
|
+
print_logging = None
|
41
45
|
|
42
46
|
else:
|
43
47
|
raise ValueError(f"Unknown log format: {config.LOG_FORMAT}")
|
@@ -63,9 +67,26 @@ def patch_logger() -> None:
|
|
63
67
|
# Use logging module for warnings.
|
64
68
|
logging.captureWarnings(True)
|
65
69
|
|
70
|
+
# Use loguru for prints.
|
71
|
+
if print_logging is not None:
|
72
|
+
builtins.print = print_logging # type: ignore[assignment] # Monkey patching, it's messy but it works.
|
73
|
+
|
66
74
|
logger.info(f"Patched logger for {config.LOG_FORMAT.value} format.")
|
67
75
|
|
68
76
|
|
77
|
+
def print_using_loguru_info(
|
78
|
+
*values: object,
|
79
|
+
sep: str = " ",
|
80
|
+
end: str = "\n",
|
81
|
+
**kwargs: t.Any,
|
82
|
+
) -> None:
|
83
|
+
message = sep.join(map(str, values)) + end
|
84
|
+
message = message.strip().replace(
|
85
|
+
"\n", "\\n"
|
86
|
+
) # Escape new lines, because otherwise logs will be broken.
|
87
|
+
logger.info(message)
|
88
|
+
|
89
|
+
|
69
90
|
def simple_warning_format(message, category, filename, lineno, line=None): # type: ignore[no-untyped-def] # Not typed in the standard library neither.
|
70
91
|
return f"{category.__name__}: {message}"
|
71
92
|
|
@@ -18,6 +18,7 @@ from prediction_market_agent_tooling.tools.utils import (
|
|
18
18
|
add_utc_timezone_validator,
|
19
19
|
check_not_none,
|
20
20
|
should_not_happen,
|
21
|
+
utcnow,
|
21
22
|
)
|
22
23
|
|
23
24
|
|
@@ -147,9 +148,18 @@ class AgentMarket(BaseModel):
|
|
147
148
|
) -> list[Bet]:
|
148
149
|
raise NotImplementedError("Subclasses must implement this method")
|
149
150
|
|
151
|
+
def is_closed(self) -> bool:
|
152
|
+
return self.close_time is not None and self.close_time <= utcnow()
|
153
|
+
|
150
154
|
def is_resolved(self) -> bool:
|
151
155
|
return self.resolution is not None
|
152
156
|
|
157
|
+
def get_liquidity(self) -> TokenAmount:
|
158
|
+
raise NotImplementedError("Subclasses must implement this method")
|
159
|
+
|
160
|
+
def has_liquidity(self) -> bool:
|
161
|
+
return self.get_liquidity().amount > 0
|
162
|
+
|
153
163
|
def has_successful_resolution(self) -> bool:
|
154
164
|
return self.resolution in [Resolution.YES, Resolution.NO]
|
155
165
|
|
@@ -174,8 +184,15 @@ class AgentMarket(BaseModel):
|
|
174
184
|
raise NotImplementedError("Subclasses must implement this method")
|
175
185
|
|
176
186
|
@classmethod
|
177
|
-
def get_positions(cls, user_id: str) -> list[Position]:
|
187
|
+
def get_positions(cls, user_id: str, liquid_only: bool = False) -> list[Position]:
|
178
188
|
"""
|
179
189
|
Get all non-zero positions a user has in any market.
|
190
|
+
|
191
|
+
If `liquid_only` is True, only return positions that can be sold.
|
180
192
|
"""
|
181
193
|
raise NotImplementedError("Subclasses must implement this method")
|
194
|
+
|
195
|
+
def can_be_traded(self) -> bool:
|
196
|
+
if self.is_closed() or not self.has_liquidity():
|
197
|
+
return False
|
198
|
+
return True
|
@@ -2,7 +2,7 @@ import typing as t
|
|
2
2
|
from datetime import datetime, timedelta
|
3
3
|
from enum import Enum
|
4
4
|
|
5
|
-
from prediction_market_agent_tooling.config import APIKeys
|
5
|
+
from prediction_market_agent_tooling.config import APIKeys
|
6
6
|
from prediction_market_agent_tooling.markets.agent_market import (
|
7
7
|
AgentMarket,
|
8
8
|
FilterBy,
|
@@ -68,7 +68,6 @@ def have_bet_on_market_since(
|
|
68
68
|
keys: APIKeys, market: AgentMarket, since: timedelta
|
69
69
|
) -> bool:
|
70
70
|
start_time = utcnow() - since
|
71
|
-
credentials = PrivateCredentials.from_api_keys(keys)
|
72
71
|
recently_betted_questions = (
|
73
72
|
set(
|
74
73
|
get_manifold_market(b.contractId).question
|
@@ -85,7 +84,7 @@ def have_bet_on_market_since(
|
|
85
84
|
set(
|
86
85
|
b.title
|
87
86
|
for b in OmenSubgraphHandler().get_bets(
|
88
|
-
better_address=
|
87
|
+
better_address=keys.bet_from_address,
|
89
88
|
start_time=start_time,
|
90
89
|
)
|
91
90
|
)
|
@@ -5,7 +5,7 @@ from datetime import datetime
|
|
5
5
|
from web3 import Web3
|
6
6
|
from web3.constants import HASH_ZERO
|
7
7
|
|
8
|
-
from prediction_market_agent_tooling.config import APIKeys
|
8
|
+
from prediction_market_agent_tooling.config import APIKeys
|
9
9
|
from prediction_market_agent_tooling.gtypes import (
|
10
10
|
ChecksumAddress,
|
11
11
|
HexAddress,
|
@@ -117,11 +117,17 @@ class OmenAgentMarket(AgentMarket):
|
|
117
117
|
else None
|
118
118
|
)
|
119
119
|
|
120
|
-
def
|
120
|
+
def get_liquidity_in_wei(self) -> Wei:
|
121
121
|
return self.get_contract().totalSupply()
|
122
122
|
|
123
123
|
def get_liquidity_in_xdai(self) -> xDai:
|
124
|
-
return wei_to_xdai(self.
|
124
|
+
return wei_to_xdai(self.get_liquidity_in_wei())
|
125
|
+
|
126
|
+
def get_liquidity(self) -> TokenAmount:
|
127
|
+
return TokenAmount(
|
128
|
+
amount=self.get_liquidity_in_xdai(),
|
129
|
+
currency=Currency.xDai,
|
130
|
+
)
|
125
131
|
|
126
132
|
def get_tiny_bet_amount(self) -> BetAmount:
|
127
133
|
return BetAmount(amount=0.00001, currency=self.currency)
|
@@ -133,13 +139,15 @@ class OmenAgentMarket(AgentMarket):
|
|
133
139
|
omen_auto_deposit: bool = True,
|
134
140
|
web3: Web3 | None = None,
|
135
141
|
) -> None:
|
142
|
+
if not self.can_be_traded():
|
143
|
+
raise ValueError(
|
144
|
+
f"Market {self.id} is not open for trading. Cannot place bet."
|
145
|
+
)
|
136
146
|
if amount.currency != self.currency:
|
137
147
|
raise ValueError(f"Omen bets are made in xDai. Got {amount.currency}.")
|
138
148
|
amount_xdai = xDai(amount.amount)
|
139
|
-
keys = APIKeys()
|
140
|
-
private_credentials = PrivateCredentials.from_api_keys(keys)
|
141
149
|
binary_omen_buy_outcome_tx(
|
142
|
-
|
150
|
+
api_keys=APIKeys(),
|
143
151
|
amount=amount_xdai,
|
144
152
|
market=self,
|
145
153
|
binary_outcome=outcome,
|
@@ -150,10 +158,12 @@ class OmenAgentMarket(AgentMarket):
|
|
150
158
|
def sell_tokens(
|
151
159
|
self, outcome: bool, amount: TokenAmount, auto_withdraw: bool = True
|
152
160
|
) -> None:
|
153
|
-
|
154
|
-
|
161
|
+
if not self.can_be_traded():
|
162
|
+
raise ValueError(
|
163
|
+
f"Market {self.id} is not open for trading. Cannot sell tokens."
|
164
|
+
)
|
155
165
|
binary_omen_sell_outcome_tx(
|
156
|
-
|
166
|
+
api_keys=APIKeys(),
|
157
167
|
amount=xDai(amount.amount),
|
158
168
|
market=self,
|
159
169
|
binary_outcome=outcome,
|
@@ -206,9 +216,9 @@ class OmenAgentMarket(AgentMarket):
|
|
206
216
|
|
207
217
|
def redeem_positions(
|
208
218
|
self,
|
209
|
-
|
219
|
+
api_keys: APIKeys,
|
210
220
|
) -> None:
|
211
|
-
for_public_key =
|
221
|
+
for_public_key = api_keys.bet_from_address
|
212
222
|
market_is_redeemable = self.market_redeemable_by(user=for_public_key)
|
213
223
|
if not market_is_redeemable:
|
214
224
|
logger.debug(
|
@@ -216,9 +226,7 @@ class OmenAgentMarket(AgentMarket):
|
|
216
226
|
)
|
217
227
|
return None
|
218
228
|
|
219
|
-
omen_redeem_full_position_tx(
|
220
|
-
private_credentials=private_credentials, market=self
|
221
|
-
)
|
229
|
+
omen_redeem_full_position_tx(api_keys=api_keys, market=self)
|
222
230
|
|
223
231
|
@staticmethod
|
224
232
|
def from_data_model(model: OmenMarket) -> "OmenAgentMarket":
|
@@ -273,9 +281,6 @@ class OmenAgentMarket(AgentMarket):
|
|
273
281
|
bets = OmenSubgraphHandler().get_bets(
|
274
282
|
better_address=better_address, start_time=start_time
|
275
283
|
)
|
276
|
-
# get unique titles
|
277
|
-
seen_titles = {bet.title: bet for bet in bets}
|
278
|
-
bets = list(seen_titles.values())
|
279
284
|
bets.sort(key=lambda x: x.creation_datetime)
|
280
285
|
return [b.to_bet() for b in bets]
|
281
286
|
|
@@ -310,7 +315,7 @@ class OmenAgentMarket(AgentMarket):
|
|
310
315
|
)
|
311
316
|
|
312
317
|
@classmethod
|
313
|
-
def get_positions(cls, user_id: str) -> list[Position]:
|
318
|
+
def get_positions(cls, user_id: str, liquid_only: bool = False) -> list[Position]:
|
314
319
|
sgh = OmenSubgraphHandler()
|
315
320
|
omen_positions = sgh.get_user_positions(
|
316
321
|
better_address=Web3.to_checksum_address(user_id),
|
@@ -338,6 +343,11 @@ class OmenAgentMarket(AgentMarket):
|
|
338
343
|
positions = []
|
339
344
|
for condition_id, omen_positions in omen_positions_dict.items():
|
340
345
|
market = cls.from_data_model(omen_markets[condition_id])
|
346
|
+
|
347
|
+
# Skip markets that cannot be traded if `liquid_only`` is True.
|
348
|
+
if liquid_only and not market.can_be_traded():
|
349
|
+
continue
|
350
|
+
|
341
351
|
amounts: dict[OutcomeStr, TokenAmount] = {}
|
342
352
|
for omen_position in omen_positions:
|
343
353
|
outecome_str = market.index_set_to_outcome_str(
|
@@ -370,7 +380,7 @@ def pick_binary_market(
|
|
370
380
|
|
371
381
|
|
372
382
|
def omen_buy_outcome_tx(
|
373
|
-
|
383
|
+
api_keys: APIKeys,
|
374
384
|
amount: xDai,
|
375
385
|
market: OmenAgentMarket,
|
376
386
|
outcome: str,
|
@@ -381,7 +391,7 @@ def omen_buy_outcome_tx(
|
|
381
391
|
Bets the given amount of xDai for the given outcome in the given market.
|
382
392
|
"""
|
383
393
|
amount_wei = xdai_to_wei(amount)
|
384
|
-
from_address_checksummed =
|
394
|
+
from_address_checksummed = api_keys.bet_from_address
|
385
395
|
|
386
396
|
market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
|
387
397
|
|
@@ -398,7 +408,7 @@ def omen_buy_outcome_tx(
|
|
398
408
|
expected_shares = remove_fraction(expected_shares, 0.01)
|
399
409
|
# Approve the market maker to withdraw our collateral token.
|
400
410
|
collateral_token_contract.approve(
|
401
|
-
|
411
|
+
api_keys=api_keys,
|
402
412
|
for_address=market_contract.address,
|
403
413
|
amount_wei=amount_wei,
|
404
414
|
web3=web3,
|
@@ -410,11 +420,11 @@ def omen_buy_outcome_tx(
|
|
410
420
|
)
|
411
421
|
if auto_deposit and collateral_token_balance < amount_wei:
|
412
422
|
collateral_token_contract.deposit(
|
413
|
-
|
423
|
+
api_keys=api_keys, amount_wei=amount_wei, web3=web3
|
414
424
|
)
|
415
425
|
# Buy shares using the deposited xDai in the collateral token.
|
416
426
|
market_contract.buy(
|
417
|
-
|
427
|
+
api_keys=api_keys,
|
418
428
|
amount_wei=amount_wei,
|
419
429
|
outcome_index=outcome_index,
|
420
430
|
min_outcome_tokens_to_buy=expected_shares,
|
@@ -423,7 +433,7 @@ def omen_buy_outcome_tx(
|
|
423
433
|
|
424
434
|
|
425
435
|
def binary_omen_buy_outcome_tx(
|
426
|
-
|
436
|
+
api_keys: APIKeys,
|
427
437
|
amount: xDai,
|
428
438
|
market: OmenAgentMarket,
|
429
439
|
binary_outcome: bool,
|
@@ -431,7 +441,7 @@ def binary_omen_buy_outcome_tx(
|
|
431
441
|
web3: Web3 | None = None,
|
432
442
|
) -> None:
|
433
443
|
omen_buy_outcome_tx(
|
434
|
-
|
444
|
+
api_keys=api_keys,
|
435
445
|
amount=amount,
|
436
446
|
market=market,
|
437
447
|
outcome=OMEN_TRUE_OUTCOME if binary_outcome else OMEN_FALSE_OUTCOME,
|
@@ -441,7 +451,7 @@ def binary_omen_buy_outcome_tx(
|
|
441
451
|
|
442
452
|
|
443
453
|
def omen_sell_outcome_tx(
|
444
|
-
|
454
|
+
api_keys: APIKeys,
|
445
455
|
amount: xDai, # The xDai value of shares to sell.
|
446
456
|
market: OmenAgentMarket,
|
447
457
|
outcome: str,
|
@@ -482,14 +492,14 @@ def omen_sell_outcome_tx(
|
|
482
492
|
|
483
493
|
# Approve the market maker to move our (all) conditional tokens.
|
484
494
|
conditional_token_contract.setApprovalForAll(
|
485
|
-
|
495
|
+
api_keys=api_keys,
|
486
496
|
for_address=market_contract.address,
|
487
497
|
approve=True,
|
488
498
|
web3=web3,
|
489
499
|
)
|
490
500
|
# Sell the shares.
|
491
501
|
market_contract.sell(
|
492
|
-
|
502
|
+
api_keys,
|
493
503
|
amount_wei,
|
494
504
|
outcome_index,
|
495
505
|
max_outcome_tokens_to_sell,
|
@@ -497,13 +507,11 @@ def omen_sell_outcome_tx(
|
|
497
507
|
)
|
498
508
|
if auto_withdraw:
|
499
509
|
# Optionally, withdraw from the collateral token back to the `from_address` wallet.
|
500
|
-
collateral_token.withdraw(
|
501
|
-
private_credentials=private_credentials, amount_wei=amount_wei, web3=web3
|
502
|
-
)
|
510
|
+
collateral_token.withdraw(api_keys=api_keys, amount_wei=amount_wei, web3=web3)
|
503
511
|
|
504
512
|
|
505
513
|
def binary_omen_sell_outcome_tx(
|
506
|
-
|
514
|
+
api_keys: APIKeys,
|
507
515
|
amount: xDai,
|
508
516
|
market: OmenAgentMarket,
|
509
517
|
binary_outcome: bool,
|
@@ -511,7 +519,7 @@ def binary_omen_sell_outcome_tx(
|
|
511
519
|
web3: Web3 | None = None,
|
512
520
|
) -> None:
|
513
521
|
omen_sell_outcome_tx(
|
514
|
-
|
522
|
+
api_keys=api_keys,
|
515
523
|
amount=amount,
|
516
524
|
market=market,
|
517
525
|
outcome=OMEN_TRUE_OUTCOME if binary_outcome else OMEN_FALSE_OUTCOME,
|
@@ -521,7 +529,7 @@ def binary_omen_sell_outcome_tx(
|
|
521
529
|
|
522
530
|
|
523
531
|
def omen_create_market_tx(
|
524
|
-
|
532
|
+
api_keys: APIKeys,
|
525
533
|
initial_funds: xDai,
|
526
534
|
question: str,
|
527
535
|
closing_time: datetime,
|
@@ -535,7 +543,7 @@ def omen_create_market_tx(
|
|
535
543
|
"""
|
536
544
|
Based on omen-exchange TypeScript code: https://github.com/protofire/omen-exchange/blob/b0b9a3e71b415d6becf21fe428e1c4fc0dad2e80/app/src/services/cpk/cpk.ts#L308
|
537
545
|
"""
|
538
|
-
from_address =
|
546
|
+
from_address = api_keys.bet_from_address
|
539
547
|
initial_funds_wei = xdai_to_wei(initial_funds)
|
540
548
|
|
541
549
|
realitio_contract = OmenRealitioContract()
|
@@ -558,7 +566,7 @@ def omen_create_market_tx(
|
|
558
566
|
|
559
567
|
# Approve the market maker to withdraw our collateral token.
|
560
568
|
collateral_token_contract.approve(
|
561
|
-
|
569
|
+
api_keys=api_keys,
|
562
570
|
for_address=factory_contract.address,
|
563
571
|
amount_wei=initial_funds_wei,
|
564
572
|
web3=web3,
|
@@ -574,13 +582,11 @@ def omen_create_market_tx(
|
|
574
582
|
and initial_funds_wei > 0
|
575
583
|
and collateral_token_balance < initial_funds_wei
|
576
584
|
):
|
577
|
-
collateral_token_contract.deposit(
|
578
|
-
private_credentials, initial_funds_wei, web3=web3
|
579
|
-
)
|
585
|
+
collateral_token_contract.deposit(api_keys, initial_funds_wei, web3=web3)
|
580
586
|
|
581
587
|
# Create the question on Realitio.
|
582
588
|
question_id = realitio_contract.askQuestion(
|
583
|
-
|
589
|
+
api_keys=api_keys,
|
584
590
|
question=question,
|
585
591
|
category=category,
|
586
592
|
outcomes=outcomes,
|
@@ -599,7 +605,7 @@ def omen_create_market_tx(
|
|
599
605
|
)
|
600
606
|
if not conditional_token_contract.does_condition_exists(condition_id, web3=web3):
|
601
607
|
conditional_token_contract.prepareCondition(
|
602
|
-
|
608
|
+
api_keys=api_keys,
|
603
609
|
question_id=question_id,
|
604
610
|
oracle_address=oracle_contract.address,
|
605
611
|
outcomes_slot_count=len(outcomes),
|
@@ -608,7 +614,7 @@ def omen_create_market_tx(
|
|
608
614
|
|
609
615
|
# Create the market.
|
610
616
|
create_market_receipt_tx = factory_contract.create2FixedProductMarketMaker(
|
611
|
-
|
617
|
+
api_keys=api_keys,
|
612
618
|
condition_id=condition_id,
|
613
619
|
fee=fee,
|
614
620
|
initial_funds_wei=initial_funds_wei,
|
@@ -627,13 +633,13 @@ def omen_create_market_tx(
|
|
627
633
|
|
628
634
|
|
629
635
|
def omen_fund_market_tx(
|
630
|
-
|
636
|
+
api_keys: APIKeys,
|
631
637
|
market: OmenAgentMarket,
|
632
638
|
funds: Wei,
|
633
639
|
auto_deposit: bool,
|
634
640
|
web3: Web3 | None = None,
|
635
641
|
) -> None:
|
636
|
-
from_address =
|
642
|
+
from_address = api_keys.bet_from_address
|
637
643
|
market_contract = market.get_contract()
|
638
644
|
collateral_token_contract = OmenCollateralTokenContract()
|
639
645
|
|
@@ -644,16 +650,16 @@ def omen_fund_market_tx(
|
|
644
650
|
and collateral_token_contract.balanceOf(for_address=from_address, web3=web3)
|
645
651
|
< funds
|
646
652
|
):
|
647
|
-
collateral_token_contract.deposit(
|
653
|
+
collateral_token_contract.deposit(api_keys, funds, web3=web3)
|
648
654
|
|
649
655
|
collateral_token_contract.approve(
|
650
|
-
|
656
|
+
api_keys=api_keys,
|
651
657
|
for_address=market_contract.address,
|
652
658
|
amount_wei=funds,
|
653
659
|
web3=web3,
|
654
660
|
)
|
655
661
|
|
656
|
-
market_contract.addFunding(
|
662
|
+
market_contract.addFunding(api_keys, funds, web3=web3)
|
657
663
|
|
658
664
|
|
659
665
|
def build_parent_collection_id() -> HexStr:
|
@@ -661,7 +667,7 @@ def build_parent_collection_id() -> HexStr:
|
|
661
667
|
|
662
668
|
|
663
669
|
def omen_redeem_full_position_tx(
|
664
|
-
|
670
|
+
api_keys: APIKeys,
|
665
671
|
market: OmenAgentMarket,
|
666
672
|
web3: Web3 | None = None,
|
667
673
|
) -> None:
|
@@ -670,7 +676,7 @@ def omen_redeem_full_position_tx(
|
|
670
676
|
to be redeemed before sending the transaction.
|
671
677
|
"""
|
672
678
|
|
673
|
-
from_address =
|
679
|
+
from_address = api_keys.bet_from_address
|
674
680
|
|
675
681
|
market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
|
676
682
|
conditional_token_contract = OmenConditionalTokenContract()
|
@@ -700,7 +706,7 @@ def omen_redeem_full_position_tx(
|
|
700
706
|
return
|
701
707
|
|
702
708
|
conditional_token_contract.redeemPositions(
|
703
|
-
|
709
|
+
api_keys=api_keys,
|
704
710
|
collateral_token_address=market.collateral_token_contract_address_checksummed,
|
705
711
|
condition_id=market.condition.id,
|
706
712
|
parent_collection_id=parent_collection_id,
|
@@ -741,7 +747,7 @@ def get_conditional_tokens_balance_for_market(
|
|
741
747
|
|
742
748
|
|
743
749
|
def omen_remove_fund_market_tx(
|
744
|
-
|
750
|
+
api_keys: APIKeys,
|
745
751
|
market: OmenAgentMarket,
|
746
752
|
shares: Wei | None,
|
747
753
|
web3: Web3 | None = None,
|
@@ -754,7 +760,7 @@ def omen_remove_fund_market_tx(
|
|
754
760
|
After we remove funding, using the `mergePositions` we get `min(shares per index)` of wxDai back, but the remaining shares can be converted back only after the market is resolved.
|
755
761
|
That can be done using the `redeem_from_all_user_positions` function below.
|
756
762
|
"""
|
757
|
-
from_address =
|
763
|
+
from_address = api_keys.bet_from_address
|
758
764
|
market_contract = market.get_contract()
|
759
765
|
original_balances = get_balances(from_address, web3=web3)
|
760
766
|
|
@@ -769,9 +775,7 @@ def omen_remove_fund_market_tx(
|
|
769
775
|
)
|
770
776
|
shares = total_shares
|
771
777
|
|
772
|
-
market_contract.removeFunding(
|
773
|
-
private_credentials=private_credentials, remove_funding=shares, web3=web3
|
774
|
-
)
|
778
|
+
market_contract.removeFunding(api_keys=api_keys, remove_funding=shares, web3=web3)
|
775
779
|
|
776
780
|
conditional_tokens = OmenConditionalTokenContract()
|
777
781
|
parent_collection_id = build_parent_collection_id()
|
@@ -784,7 +788,7 @@ def omen_remove_fund_market_tx(
|
|
784
788
|
amount_to_merge = min(amount_per_index_set.values())
|
785
789
|
|
786
790
|
result = conditional_tokens.mergePositions(
|
787
|
-
|
791
|
+
api_keys=api_keys,
|
788
792
|
collateral_token_address=market.collateral_token_contract_address_checksummed,
|
789
793
|
parent_collection_id=parent_collection_id,
|
790
794
|
conditionId=market.condition.id,
|
@@ -802,13 +806,13 @@ def omen_remove_fund_market_tx(
|
|
802
806
|
|
803
807
|
|
804
808
|
def redeem_from_all_user_positions(
|
805
|
-
|
809
|
+
api_keys: APIKeys,
|
806
810
|
web3: Web3 | None = None,
|
807
811
|
) -> None:
|
808
812
|
"""
|
809
813
|
Redeems from all user positions where the user didn't redeem yet.
|
810
814
|
"""
|
811
|
-
public_key =
|
815
|
+
public_key = api_keys.bet_from_address
|
812
816
|
|
813
817
|
conditional_token_contract = OmenConditionalTokenContract()
|
814
818
|
user_positions = OmenSubgraphHandler().get_user_positions(
|
@@ -832,7 +836,7 @@ def redeem_from_all_user_positions(
|
|
832
836
|
|
833
837
|
original_balances = get_balances(public_key, web3)
|
834
838
|
conditional_token_contract.redeemPositions(
|
835
|
-
|
839
|
+
api_keys=api_keys,
|
836
840
|
collateral_token_address=user_position.position.collateral_token_contract_address_checksummed,
|
837
841
|
condition_id=condition_id,
|
838
842
|
parent_collection_id=build_parent_collection_id(),
|