prediction-market-agent-tooling 0.43.1__py3-none-any.whl → 0.43.4__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 (24) hide show
  1. prediction_market_agent_tooling/abis/depositablewrapper_erc20.abi.json +279 -0
  2. prediction_market_agent_tooling/abis/erc20.abi.json +221 -314
  3. prediction_market_agent_tooling/abis/erc4626.abi.json +623 -0
  4. prediction_market_agent_tooling/abis/proxy.abi.json +24 -0
  5. prediction_market_agent_tooling/deploy/agent.py +10 -2
  6. prediction_market_agent_tooling/deploy/agent_example.py +4 -1
  7. prediction_market_agent_tooling/gtypes.py +1 -1
  8. prediction_market_agent_tooling/markets/agent_market.py +2 -1
  9. prediction_market_agent_tooling/markets/manifold/manifold.py +3 -2
  10. prediction_market_agent_tooling/markets/omen/data_models.py +2 -1
  11. prediction_market_agent_tooling/markets/omen/omen.py +73 -38
  12. prediction_market_agent_tooling/markets/omen/omen_contracts.py +43 -12
  13. prediction_market_agent_tooling/markets/omen/omen_resolving.py +17 -6
  14. prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +9 -0
  15. prediction_market_agent_tooling/markets/polymarket/data_models_web.py +83 -83
  16. prediction_market_agent_tooling/markets/polymarket/polymarket.py +2 -1
  17. prediction_market_agent_tooling/tools/contract.py +303 -11
  18. prediction_market_agent_tooling/tools/is_predictable.py +4 -2
  19. {prediction_market_agent_tooling-0.43.1.dist-info → prediction_market_agent_tooling-0.43.4.dist-info}/METADATA +1 -1
  20. {prediction_market_agent_tooling-0.43.1.dist-info → prediction_market_agent_tooling-0.43.4.dist-info}/RECORD +23 -21
  21. prediction_market_agent_tooling/abis/wxdai.abi.json +0 -279
  22. {prediction_market_agent_tooling-0.43.1.dist-info → prediction_market_agent_tooling-0.43.4.dist-info}/LICENSE +0 -0
  23. {prediction_market_agent_tooling-0.43.1.dist-info → prediction_market_agent_tooling-0.43.4.dist-info}/WHEEL +0 -0
  24. {prediction_market_agent_tooling-0.43.1.dist-info → prediction_market_agent_tooling-0.43.4.dist-info}/entry_points.txt +0 -0
@@ -34,7 +34,7 @@ class Event(BaseModel):
34
34
  slug: str
35
35
  ticker: str
36
36
  title: str
37
- series: str | None
37
+ series: t.Any | None = None
38
38
 
39
39
 
40
40
  class Event1(BaseModel):
@@ -46,7 +46,7 @@ class Market1(BaseModel):
46
46
  slug: str
47
47
  question: str
48
48
  image: str
49
- volume: USDC | None
49
+ volume: USDC | None = None
50
50
  outcomes: list[str]
51
51
  outcomePrices: list[USDC]
52
52
  active: bool
@@ -54,7 +54,7 @@ class Market1(BaseModel):
54
54
  closed: bool
55
55
  orderPriceMinTickSize: USDC
56
56
  clobTokenIds: str
57
- events: list[Event1]
57
+ events: list[Event1] | None = None
58
58
 
59
59
 
60
60
  class ResolutionData(BaseModel):
@@ -77,98 +77,98 @@ class Market(BaseModel):
77
77
  question: str
78
78
  conditionId: str
79
79
  slug: str
80
- twitterCardImage: t.Any | None
80
+ twitterCardImage: t.Any | None = None
81
81
  resolutionSource: str
82
82
  endDate: datetime
83
- category: t.Any | None
84
- ammType: t.Any | None
83
+ category: t.Any | None = None
84
+ ammType: t.Any | None = None
85
85
  description: str
86
- liquidity: str | None
86
+ liquidity: str | None = None
87
87
  startDate: datetime
88
88
  createdAt: datetime
89
- xAxisValue: t.Any | None
90
- yAxisValue: t.Any | None
91
- denominationToken: t.Any | None
92
- fee: str | None
93
- lowerBound: t.Any | None
94
- upperBound: t.Any | None
89
+ xAxisValue: t.Any | None = None
90
+ yAxisValue: t.Any | None = None
91
+ denominationToken: t.Any | None = None
92
+ fee: str | None = None
93
+ lowerBound: t.Any | None = None
94
+ upperBound: t.Any | None = None
95
95
  outcomes: list[str]
96
96
  image: str
97
97
  icon: str
98
- imageOptimized: t.Any | None
99
- iconOptimized: t.Any | None
98
+ imageOptimized: t.Any | None = None
99
+ iconOptimized: t.Any | None = None
100
100
  outcomePrices: list[USDC]
101
- volume: USDC | None
101
+ volume: USDC | None = None
102
102
  active: bool
103
- marketType: str | None
104
- formatType: t.Any | None
105
- lowerBoundDate: t.Any | None
106
- upperBoundDate: t.Any | None
103
+ marketType: str | None = None
104
+ formatType: t.Any | None = None
105
+ lowerBoundDate: t.Any | None = None
106
+ upperBoundDate: t.Any | None = None
107
107
  closed: bool
108
108
  marketMakerAddress: HexAddress
109
- closedTime: datetime | None
110
- wideFormat: bool | None
109
+ closedTime: datetime | None = None
110
+ wideFormat: bool | None = None
111
111
  new: bool
112
- sentDiscord: t.Any | None
113
- mailchimpTag: t.Any | None
112
+ sentDiscord: t.Any | None = None
113
+ mailchimpTag: t.Any | None = None
114
114
  featured: bool
115
115
  submitted_by: str
116
- subcategory: t.Any | None
117
- categoryMailchimpTag: t.Any | None
116
+ subcategory: t.Any | None = None
117
+ categoryMailchimpTag: t.Any | None = None
118
118
  archived: bool
119
119
  resolvedBy: str
120
120
  restricted: bool
121
121
  groupItemTitle: str
122
122
  groupItemThreshold: str
123
123
  questionID: str
124
- umaEndDate: t.Any | None
124
+ umaEndDate: t.Any | None = None
125
125
  enableOrderBook: bool
126
126
  orderPriceMinTickSize: float
127
127
  orderMinSize: int
128
- umaResolutionStatus: t.Any | None
129
- curationOrder: t.Any | None
130
- volumeNum: USDC | None
131
- liquidityNum: float | None
132
- endDateIso: datetime | None
133
- startDateIso: datetime | None
134
- umaEndDateIso: datetime | None
135
- commentsEnabled: bool | None
136
- disqusThread: t.Any | None
137
- gameStartTime: datetime | None
138
- secondsDelay: int | None
128
+ umaResolutionStatus: t.Any | None = None
129
+ curationOrder: t.Any | None = None
130
+ volumeNum: USDC | None = None
131
+ liquidityNum: float | None = None
132
+ endDateIso: datetime | None = None
133
+ startDateIso: datetime | None = None
134
+ umaEndDateIso: datetime | None = None
135
+ commentsEnabled: bool | None = None
136
+ disqusThread: t.Any | None = None
137
+ gameStartTime: datetime | None = None
138
+ secondsDelay: int | None = None
139
139
  clobTokenIds: list[str]
140
- liquidityAmm: float | None
141
- liquidityClob: float | None
142
- makerBaseFee: int | None
143
- takerBaseFee: int | None
144
- negRisk: t.Any | None
145
- negRiskRequestID: t.Any | None
146
- negRiskMarketID: t.Any | None
140
+ liquidityAmm: float | None = None
141
+ liquidityClob: float | None = None
142
+ makerBaseFee: int | None = None
143
+ takerBaseFee: int | None = None
144
+ negRisk: t.Any | None = None
145
+ negRiskRequestID: t.Any | None = None
146
+ negRiskMarketID: t.Any | None = None
147
147
  events: list[Event]
148
148
  markets: list[Market1]
149
- lower_bound_date: t.Any | None
150
- upper_bound_date: t.Any | None
151
- market_type: str | None
149
+ lower_bound_date: t.Any | None = None
150
+ upper_bound_date: t.Any | None = None
151
+ market_type: str | None = None
152
152
  resolution_source: str
153
153
  end_date: str
154
- amm_type: t.Any | None
155
- x_axis_value: t.Any | None
156
- y_axis_value: t.Any | None
157
- denomination_token: t.Any | None
154
+ amm_type: t.Any | None = None
155
+ x_axis_value: t.Any | None = None
156
+ y_axis_value: t.Any | None = None
157
+ denomination_token: t.Any | None = None
158
158
  resolved_by: str
159
- upper_bound: t.Any | None
160
- lower_bound: t.Any | None
159
+ upper_bound: t.Any | None = None
160
+ lower_bound: t.Any | None = None
161
161
  created_at: str
162
- updated_at: t.Any | None
163
- closed_time: t.Any | None
164
- wide_format: bool | None
165
- volume_num: USDC | None
166
- liquidity_num: USDC | None
162
+ updated_at: t.Any | None = None
163
+ closed_time: t.Any | None = None
164
+ wide_format: bool | None = None
165
+ volume_num: USDC | None = None
166
+ liquidity_num: USDC | None = None
167
167
  image_raw: str
168
168
  resolutionData: ResolutionData
169
169
 
170
170
  @field_validator("closedTime", mode="before")
171
- def field_validator_closedTime(cls, v: str | None) -> str | None:
171
+ def field_validator_closedTime(cls, v: str | None = None) -> str | None:
172
172
  return v.replace("+00", "") if v else None
173
173
 
174
174
  @property
@@ -232,7 +232,7 @@ class PolymarketFullMarket(BaseModel):
232
232
  ticker: str
233
233
  slug: str
234
234
  title: str
235
- subtitle: t.Any | None
235
+ subtitle: t.Any | None = None
236
236
  description: str
237
237
  commentCount: int
238
238
  resolutionSource: str
@@ -240,35 +240,35 @@ class PolymarketFullMarket(BaseModel):
240
240
  endDate: datetime
241
241
  image: str
242
242
  icon: str
243
- featuredImage: str | None
243
+ featuredImage: str | None = None
244
244
  active: bool
245
245
  closed: bool
246
246
  archived: bool
247
247
  new: bool
248
248
  featured: bool
249
249
  restricted: bool
250
- liquidity: USDC | None
251
- volume: USDC | None
252
- volume24hr: USDC | None
253
- competitive: float | None
254
- openInterest: int | None
255
- sortBy: str | None
250
+ liquidity: USDC | None = None
251
+ volume: USDC | None = None
252
+ volume24hr: USDC | None = None
253
+ competitive: float | None = None
254
+ openInterest: int | None = None
255
+ sortBy: str | None = None
256
256
  createdAt: datetime
257
- commentsEnabled: bool | None
258
- disqusThread: t.Any | None
257
+ commentsEnabled: bool | None = None
258
+ disqusThread: t.Any | None = None
259
259
  updatedAt: datetime
260
260
  enableOrderBook: bool
261
- liquidityAmm: float | None
262
- liquidityClob: float | None
263
- imageOptimized: ImageOptimized | None
264
- iconOptimized: IconOptimized | None
265
- featuredImageOptimized: str | None
266
- negRisk: t.Any | None
267
- negRiskMarketID: t.Any | None
268
- negRiskFeeBips: t.Any | None
261
+ liquidityAmm: float | None = None
262
+ liquidityClob: float | None = None
263
+ imageOptimized: ImageOptimized | None = None
264
+ iconOptimized: IconOptimized | None = None
265
+ featuredImageOptimized: str | None = None
266
+ negRisk: t.Any | None = None
267
+ negRiskMarketID: t.Any | None = None
268
+ negRiskFeeBips: t.Any | None = None
269
269
  markets: list[Market]
270
270
  categories: list[Category] | None = None
271
- series: t.Any | None
271
+ series: t.Any | None = None
272
272
  image_raw: str
273
273
 
274
274
  @property
@@ -355,12 +355,12 @@ class State(BaseModel):
355
355
  ) # It's none if you go to the website and it says "Oops...we didn't forecast this".
356
356
  dataUpdateCount: int
357
357
  dataUpdatedAt: int
358
- error: t.Any | None
358
+ error: t.Any | None = None
359
359
  errorUpdateCount: int
360
360
  errorUpdatedAt: int
361
361
  fetchFailureCount: int
362
- fetchFailureReason: t.Any | None
363
- fetchMeta: t.Any | None
362
+ fetchFailureReason: t.Any | None = None
363
+ fetchMeta: t.Any | None = None
364
364
  isInvalidated: bool
365
365
  status: str
366
366
  fetchStatus: str
@@ -381,7 +381,7 @@ class PageProps(BaseModel):
381
381
  key: str
382
382
  dehydratedState: DehydratedState
383
383
  eslug: str
384
- mslug: str | None
384
+ mslug: str | None = None
385
385
  isSingleMarket: bool
386
386
 
387
387
 
@@ -41,7 +41,8 @@ class PolymarketAgentMarket(AgentMarket):
41
41
  volume=None,
42
42
  )
43
43
 
44
- def get_tiny_bet_amount(self) -> BetAmount:
44
+ @classmethod
45
+ def get_tiny_bet_amount(cls) -> BetAmount:
45
46
  raise NotImplementedError("TODO: Implement to allow betting on Polymarket.")
46
47
 
47
48
  def place_bet(self, outcome: bool, amount: BetAmount) -> None:
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import os
2
3
  import time
3
4
  import typing as t
4
5
  from contextlib import contextmanager
@@ -151,11 +152,33 @@ class ContractBaseClass(BaseModel):
151
152
  return Web3(Web3.HTTPProvider(cls.CHAIN_RPC_URL))
152
153
 
153
154
 
155
+ class ContractProxyBaseClass(ContractBaseClass):
156
+ """
157
+ Contract base class for proxy contracts.
158
+ """
159
+
160
+ abi: ABI = abi_field_validator(
161
+ os.path.join(
162
+ os.path.dirname(os.path.realpath(__file__)), "../abis/proxy.abi.json"
163
+ )
164
+ )
165
+
166
+ def implementation(self, web3: Web3 | None = None) -> ChecksumAddress:
167
+ address = self.call("implementation", web3=web3)
168
+ return Web3.to_checksum_address(address)
169
+
170
+
154
171
  class ContractERC20BaseClass(ContractBaseClass):
155
172
  """
156
173
  Contract base class extended by ERC-20 standard methods.
157
174
  """
158
175
 
176
+ abi: ABI = abi_field_validator(
177
+ os.path.join(
178
+ os.path.dirname(os.path.realpath(__file__)), "../abis/erc20.abi.json"
179
+ )
180
+ )
181
+
159
182
  def approve(
160
183
  self,
161
184
  api_keys: APIKeys,
@@ -175,6 +198,41 @@ class ContractERC20BaseClass(ContractBaseClass):
175
198
  web3=web3,
176
199
  )
177
200
 
201
+ def transferFrom(
202
+ self,
203
+ api_keys: APIKeys,
204
+ sender: ChecksumAddress,
205
+ recipient: ChecksumAddress,
206
+ amount_wei: Wei,
207
+ tx_params: t.Optional[TxParams] = None,
208
+ web3: Web3 | None = None,
209
+ ) -> TxReceipt:
210
+ return self.send(
211
+ api_keys=api_keys,
212
+ function_name="transferFrom",
213
+ function_params=[sender, recipient, amount_wei],
214
+ tx_params=tx_params,
215
+ web3=web3,
216
+ )
217
+
218
+ def balanceOf(self, for_address: ChecksumAddress, web3: Web3 | None = None) -> Wei:
219
+ balance: Wei = self.call("balanceOf", [for_address], web3=web3)
220
+ return balance
221
+
222
+
223
+ class ContractDepositableWrapperERC20BaseClass(ContractERC20BaseClass):
224
+ """
225
+ ERC-20 standard base class extended for wrapper tokens.
226
+ Altough this is not a standard, it's seems to be a common pattern for wrapped tokens (at least it checks out for wxDai and wETH).
227
+ """
228
+
229
+ abi: ABI = abi_field_validator(
230
+ os.path.join(
231
+ os.path.dirname(os.path.realpath(__file__)),
232
+ "../abis/depositablewrapper_erc20.abi.json",
233
+ )
234
+ )
235
+
178
236
  def deposit(
179
237
  self,
180
238
  api_keys: APIKeys,
@@ -190,41 +248,93 @@ class ContractERC20BaseClass(ContractBaseClass):
190
248
  web3=web3,
191
249
  )
192
250
 
193
- def transferFrom(
251
+ def withdraw(
194
252
  self,
195
253
  api_keys: APIKeys,
196
- sender: ChecksumAddress,
197
- recipient: ChecksumAddress,
198
254
  amount_wei: Wei,
199
255
  tx_params: t.Optional[TxParams] = None,
200
256
  web3: Web3 | None = None,
201
257
  ) -> TxReceipt:
202
258
  return self.send(
203
259
  api_keys=api_keys,
204
- function_name="transferFrom",
205
- function_params=[sender, recipient, amount_wei],
260
+ function_name="withdraw",
261
+ function_params=[amount_wei],
206
262
  tx_params=tx_params,
207
263
  web3=web3,
208
264
  )
209
265
 
210
- def withdraw(
266
+
267
+ class ContractERC4626BaseClass(ContractERC20BaseClass):
268
+ """
269
+ Class for ERC-4626, which is a superset for ERC-20.
270
+ """
271
+
272
+ abi: ABI = abi_field_validator(
273
+ os.path.join(
274
+ os.path.dirname(os.path.realpath(__file__)), "../abis/erc4626.abi.json"
275
+ )
276
+ )
277
+
278
+ def asset(self, web3: Web3 | None = None) -> ChecksumAddress:
279
+ address = self.call("asset", web3=web3)
280
+ return Web3.to_checksum_address(address)
281
+
282
+ def deposit(
211
283
  self,
212
284
  api_keys: APIKeys,
213
285
  amount_wei: Wei,
286
+ receiver: ChecksumAddress,
214
287
  tx_params: t.Optional[TxParams] = None,
215
288
  web3: Web3 | None = None,
216
289
  ) -> TxReceipt:
217
290
  return self.send(
218
291
  api_keys=api_keys,
219
- function_name="withdraw",
220
- function_params=[amount_wei],
292
+ function_name="deposit",
293
+ function_params=[amount_wei, receiver],
221
294
  tx_params=tx_params,
222
295
  web3=web3,
223
296
  )
224
297
 
225
- def balanceOf(self, for_address: ChecksumAddress, web3: Web3 | None = None) -> Wei:
226
- balance: Wei = self.call("balanceOf", [for_address], web3=web3)
227
- return balance
298
+ def convertToShares(self, assets: Wei, web3: Web3 | None = None) -> Wei:
299
+ shares: Wei = self.call("convertToShares", [assets], web3=web3)
300
+ return shares
301
+
302
+ def convertToAssets(self, shares: Wei, web3: Web3 | None = None) -> Wei:
303
+ assets: Wei = self.call("convertToAssets", [shares], web3=web3)
304
+ return assets
305
+
306
+ def get_asset_token_contract(
307
+ self, web3: Web3 | None = None
308
+ ) -> ContractERC20BaseClass | ContractDepositableWrapperERC20BaseClass:
309
+ web3 = web3 or self.get_web3()
310
+ contract = init_erc4626_or_wrappererc20_or_erc20_contract(
311
+ self.asset(), web3=web3
312
+ )
313
+ assert not isinstance(
314
+ contract, ContractERC4626OnGnosisChain
315
+ ), "Asset token should be either Depositable Wrapper ERC-20 or ERC-20." # Shrinking down possible types.
316
+ return contract
317
+
318
+ def get_asset_token_balance(
319
+ self, for_address: ChecksumAddress, web3: Web3 | None = None
320
+ ) -> Wei:
321
+ asset_token_contract = self.get_asset_token_contract(web3=web3)
322
+ return asset_token_contract.balanceOf(for_address, web3=web3)
323
+
324
+ def deposit_asset_token(
325
+ self, asset_value: Wei, api_keys: APIKeys, web3: Web3 | None = None
326
+ ) -> TxReceipt:
327
+ for_address = api_keys.bet_from_address
328
+ web3 = web3 or self.get_web3()
329
+
330
+ asset_token_contract = self.get_asset_token_contract(web3=web3)
331
+ # Approve vault to withdraw the erc-20 token from the user.
332
+ asset_token_contract.approve(api_keys, self.address, asset_value, web3=web3)
333
+
334
+ # Deposit asset token (erc20) and we will receive shares in this vault.
335
+ receipt = self.deposit(api_keys, asset_value, for_address, web3=web3)
336
+
337
+ return receipt
228
338
 
229
339
 
230
340
  class ContractOnGnosisChain(ContractBaseClass):
@@ -236,7 +346,189 @@ class ContractOnGnosisChain(ContractBaseClass):
236
346
  CHAIN_RPC_URL = GNOSIS_RPC_URL
237
347
 
238
348
 
349
+ class ContractProxyOnGnosisChain(ContractProxyBaseClass, ContractOnGnosisChain):
350
+ """
351
+ Proxy contract base class with Gnosis Chain configuration.
352
+ """
353
+
354
+
239
355
  class ContractERC20OnGnosisChain(ContractERC20BaseClass, ContractOnGnosisChain):
240
356
  """
241
357
  ERC-20 standard base class with Gnosis Chain configuration.
242
358
  """
359
+
360
+
361
+ class ContractDepositableWrapperERC20OnGnosisChain(
362
+ ContractDepositableWrapperERC20BaseClass, ContractOnGnosisChain
363
+ ):
364
+ """
365
+ Depositable Wrapper ERC-20 standard base class with Gnosis Chain configuration.
366
+ """
367
+
368
+
369
+ class ContractERC4626OnGnosisChain(ContractERC4626BaseClass, ContractOnGnosisChain):
370
+ """
371
+ ERC-4626 standard base class with Gnosis Chain configuration.
372
+ """
373
+
374
+
375
+ def contract_implements_function(
376
+ contract_address: ChecksumAddress,
377
+ function_name: str,
378
+ web3: Web3,
379
+ function_arg_types: list[str] | None = None,
380
+ look_for_proxy_contract: bool = True,
381
+ ) -> bool:
382
+ function_signature = f"{function_name}({','.join(function_arg_types or [])})"
383
+ function_hash = web3.keccak(text=function_signature)[0:4].hex()[2:]
384
+ contract_code = web3.eth.get_code(contract_address).hex()
385
+ implements = function_hash in contract_code
386
+ if (
387
+ not implements
388
+ and look_for_proxy_contract
389
+ and contract_implements_function(
390
+ contract_address, "implementation", web3, look_for_proxy_contract=False
391
+ )
392
+ ):
393
+ implementation_address = ContractProxyOnGnosisChain(
394
+ address=contract_address
395
+ ).implementation()
396
+ implements = contract_implements_function(
397
+ implementation_address,
398
+ function_name=function_name,
399
+ web3=web3,
400
+ function_arg_types=function_arg_types,
401
+ look_for_proxy_contract=False,
402
+ )
403
+ return implements
404
+
405
+
406
+ def init_erc4626_or_wrappererc20_or_erc20_contract(
407
+ address: ChecksumAddress,
408
+ web3: Web3,
409
+ ) -> (
410
+ ContractERC20BaseClass
411
+ | ContractERC4626BaseClass
412
+ | ContractDepositableWrapperERC20BaseClass
413
+ ):
414
+ """
415
+ Checks if the given contract is Depositable ERC-20, ERC-20 or ERC-4626 and returns the appropriate class instance.
416
+ Throws an error if the contract is neither of them.
417
+ """
418
+ if contract_implements_function(address, "asset", web3=web3):
419
+ return ContractERC4626BaseClass(address=address)
420
+
421
+ elif contract_implements_function(
422
+ address,
423
+ "deposit",
424
+ web3=web3,
425
+ ):
426
+ return ContractDepositableWrapperERC20BaseClass(address=address)
427
+
428
+ elif contract_implements_function(
429
+ address,
430
+ "balanceOf",
431
+ web3=web3,
432
+ function_arg_types=["address"],
433
+ ):
434
+ return ContractERC20BaseClass(address=address)
435
+
436
+ else:
437
+ raise ValueError(
438
+ f"Contract at {address} on Gnosis Chain is neither WrapperERC-20, ERC-20 nor ERC-4626."
439
+ )
440
+
441
+
442
+ def auto_deposit_collateral_token(
443
+ collateral_token_contract: (
444
+ ContractERC20BaseClass
445
+ | ContractERC4626BaseClass
446
+ | ContractDepositableWrapperERC20BaseClass
447
+ ),
448
+ amount_wei: Wei,
449
+ api_keys: APIKeys,
450
+ web3: Web3 | None,
451
+ ) -> None:
452
+ for_address = api_keys.bet_from_address
453
+ # This might be in shares, if it's an erc-4626 token.
454
+ collateral_token_balance = collateral_token_contract.balanceOf(
455
+ for_address=for_address, web3=web3
456
+ )
457
+
458
+ if isinstance(collateral_token_contract, ContractERC4626BaseClass):
459
+ # In the more complex case, we need to deposit into the saving token, out of the erc-20 token.
460
+ # We need to compare with shares, because if erc-4626 is used, the liquidity in market will be in shares as well.
461
+ if collateral_token_balance < collateral_token_contract.convertToShares(
462
+ amount_wei
463
+ ):
464
+ asset_token_contract = collateral_token_contract.get_asset_token_contract(
465
+ web3=web3
466
+ )
467
+
468
+ # If the asset token is Depositable Wrapper ERC-20, we can deposit it, in case we don't have enough.
469
+ if (
470
+ collateral_token_contract.get_asset_token_balance(for_address, web3)
471
+ < amount_wei
472
+ ):
473
+ if isinstance(
474
+ asset_token_contract, ContractDepositableWrapperERC20BaseClass
475
+ ):
476
+ asset_token_contract.deposit(api_keys, amount_wei, web3=web3)
477
+ else:
478
+ raise ValueError(
479
+ f"Not enough of the asset token, but it's not a depositable wrapper token that we can deposit automatically."
480
+ )
481
+
482
+ collateral_token_contract.deposit_asset_token(amount_wei, api_keys, web3)
483
+
484
+ elif isinstance(
485
+ collateral_token_contract, ContractDepositableWrapperERC20BaseClass
486
+ ):
487
+ # If the collateral token is Depositable Wrapper ERC-20, it's a simple case where we can just deposit it, if needed.
488
+ if collateral_token_balance < amount_wei:
489
+ collateral_token_contract.deposit(api_keys, amount_wei, web3=web3)
490
+
491
+ elif isinstance(collateral_token_contract, ContractERC20BaseClass):
492
+ if collateral_token_balance < amount_wei:
493
+ raise ValueError(
494
+ f"Not enough of the collateral token, but it's not a wrapper token that we can deposit automatically."
495
+ )
496
+
497
+ else:
498
+ raise RuntimeError("Bug in our logic! :(")
499
+
500
+
501
+ def asset_or_shares(
502
+ collateral_token_contract: (
503
+ ContractERC20BaseClass
504
+ | ContractERC4626BaseClass
505
+ | ContractDepositableWrapperERC20BaseClass
506
+ ),
507
+ amount_wei: Wei,
508
+ ) -> Wei:
509
+ return (
510
+ collateral_token_contract.convertToShares(amount_wei)
511
+ if isinstance(collateral_token_contract, ContractERC4626BaseClass)
512
+ else amount_wei
513
+ )
514
+
515
+
516
+ def to_gnosis_chain_contract(
517
+ contract: (
518
+ ContractDepositableWrapperERC20BaseClass
519
+ | ContractERC4626BaseClass
520
+ | ContractERC20BaseClass
521
+ ),
522
+ ) -> (
523
+ ContractDepositableWrapperERC20OnGnosisChain
524
+ | ContractERC4626OnGnosisChain
525
+ | ContractERC20OnGnosisChain
526
+ ):
527
+ if isinstance(contract, ContractERC4626BaseClass):
528
+ return ContractERC4626OnGnosisChain(address=contract.address)
529
+ elif isinstance(contract, ContractDepositableWrapperERC20BaseClass):
530
+ return ContractDepositableWrapperERC20OnGnosisChain(address=contract.address)
531
+ elif isinstance(contract, ContractERC20BaseClass):
532
+ return ContractERC20OnGnosisChain(address=contract.address)
533
+ else:
534
+ raise ValueError("Unsupported contract type")
@@ -76,6 +76,7 @@ def is_predictable_binary(
76
76
  question: str,
77
77
  engine: str = "gpt-4-1106-preview",
78
78
  prompt_template: str = QUESTION_IS_PREDICTABLE_BINARY_PROMPT,
79
+ max_tokens: int = 1024,
79
80
  ) -> bool:
80
81
  """
81
82
  Evaluate if the question is actually answerable.
@@ -95,7 +96,7 @@ def is_predictable_binary(
95
96
 
96
97
  prompt = ChatPromptTemplate.from_template(template=prompt_template)
97
98
  messages = prompt.format_messages(question=question)
98
- completion = str(llm(messages, max_tokens=512).content)
99
+ completion = str(llm(messages, max_tokens=max_tokens).content)
99
100
 
100
101
  return parse_decision_yes_no_completion(question, completion)
101
102
 
@@ -106,6 +107,7 @@ def is_predictable_without_description(
106
107
  description: str,
107
108
  engine: str = "gpt-4-1106-preview",
108
109
  prompt_template: str = QUESTION_IS_PREDICTABLE_WITHOUT_DESCRIPTION_PROMPT,
110
+ max_tokens: int = 1024,
109
111
  ) -> bool:
110
112
  """
111
113
  Evaluate if the question is fully self-contained.
@@ -130,7 +132,7 @@ def is_predictable_without_description(
130
132
  question=question,
131
133
  description=description,
132
134
  )
133
- completion = str(llm(messages, max_tokens=512).content)
135
+ completion = str(llm(messages, max_tokens=max_tokens).content)
134
136
 
135
137
  return parse_decision_yes_no_completion(question, completion)
136
138
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prediction-market-agent-tooling
3
- Version: 0.43.1
3
+ Version: 0.43.4
4
4
  Summary: Tools to benchmark, deploy and monitor prediction market agents.
5
5
  Author: Gnosis
6
6
  Requires-Python: >=3.10,<3.12