prediction-market-agent-tooling 0.28.0__tar.gz → 0.30.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.
Files changed (71) hide show
  1. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/PKG-INFO +1 -1
  2. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/loggers.py +3 -1
  3. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/agent_market.py +5 -0
  4. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/manifold/manifold.py +5 -0
  5. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/omen/data_models.py +1 -1
  6. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/omen/omen.py +4 -0
  7. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/omen/omen_resolving.py +7 -1
  8. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/polymarket/api.py +30 -11
  9. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/polymarket/data_models.py +4 -4
  10. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/polymarket/data_models_web.py +26 -2
  11. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/polymarket/utils.py +5 -1
  12. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/is_predictable.py +6 -1
  13. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/pyproject.toml +1 -1
  14. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/LICENSE +0 -0
  15. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/README.md +0 -0
  16. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/abis/erc20.abi.json +0 -0
  17. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/abis/omen_dxdao.abi.json +0 -0
  18. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/abis/omen_fpmm.abi.json +0 -0
  19. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json +0 -0
  20. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/abis/omen_fpmm_factory.abi.json +0 -0
  21. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/abis/omen_kleros.abi.json +0 -0
  22. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/abis/omen_oracle.abi.json +0 -0
  23. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/abis/omen_realitio.abi.json +0 -0
  24. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/abis/wxdai.abi.json +0 -0
  25. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/benchmark/__init__.py +0 -0
  26. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/benchmark/agents.py +0 -0
  27. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/benchmark/benchmark.py +0 -0
  28. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/benchmark/utils.py +0 -0
  29. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/config.py +0 -0
  30. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/deploy/agent.py +0 -0
  31. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/deploy/agent_example.py +0 -0
  32. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/deploy/constants.py +0 -0
  33. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/deploy/gcp/deploy.py +0 -0
  34. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/deploy/gcp/kubernetes_models.py +0 -0
  35. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/deploy/gcp/utils.py +0 -0
  36. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/gtypes.py +0 -0
  37. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/categorize.py +0 -0
  38. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/data_models.py +0 -0
  39. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/manifold/__init__.py +0 -0
  40. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/manifold/api.py +0 -0
  41. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/manifold/data_models.py +0 -0
  42. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/manifold/utils.py +0 -0
  43. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/markets.py +0 -0
  44. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/omen/__init__.py +0 -0
  45. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/omen/omen_contracts.py +0 -0
  46. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/omen/omen_subgraph_handler.py +0 -0
  47. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/markets/polymarket/polymarket.py +0 -0
  48. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/monitor/langfuse/langfuse_wrapper.py +0 -0
  49. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/monitor/markets/manifold.py +0 -0
  50. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/monitor/markets/omen.py +0 -0
  51. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/monitor/markets/polymarket.py +0 -0
  52. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/monitor/monitor.py +0 -0
  53. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/monitor/monitor_app.py +0 -0
  54. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/monitor/monitor_settings.py +0 -0
  55. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/py.typed +0 -0
  56. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/balances.py +0 -0
  57. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/betting_strategies/kelly_criterion.py +0 -0
  58. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/betting_strategies/market_moving.py +0 -0
  59. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/betting_strategies/minimum_bet_to_win.py +0 -0
  60. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/betting_strategies/stretch_bet_between.py +0 -0
  61. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/cache.py +0 -0
  62. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/contract.py +0 -0
  63. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/costs.py +0 -0
  64. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/gnosis_rpc.py +0 -0
  65. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/google.py +0 -0
  66. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/hexbytes_custom.py +0 -0
  67. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/parallelism.py +0 -0
  68. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/safe.py +0 -0
  69. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/singleton.py +0 -0
  70. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/utils.py +0 -0
  71. {prediction_market_agent_tooling-0.28.0 → prediction_market_agent_tooling-0.30.0}/prediction_market_agent_tooling/tools/web3_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prediction-market-agent-tooling
3
- Version: 0.28.0
3
+ Version: 0.30.0
4
4
  Summary: Tools to benchmark, deploy and monitor prediction market agents.
5
5
  Author: Gnosis
6
6
  Requires-Python: >=3.10,<3.12
@@ -88,7 +88,9 @@ def print_using_loguru_info(
88
88
 
89
89
 
90
90
  def simple_warning_format(message, category, filename, lineno, line=None): # type: ignore[no-untyped-def] # Not typed in the standard library neither.
91
- return f"{category.__name__}: {message}"
91
+ return f"{category.__name__}: {message}".strip().replace(
92
+ "\n", "\\n"
93
+ ) # Escape new lines, because otherwise logs will be broken.
92
94
 
93
95
 
94
96
  if not getattr(logger, "_patched", False):
@@ -5,6 +5,7 @@ from enum import Enum
5
5
  from eth_typing import ChecksumAddress
6
6
  from pydantic import BaseModel, field_validator
7
7
 
8
+ from prediction_market_agent_tooling.config import APIKeys
8
9
  from prediction_market_agent_tooling.gtypes import Probability
9
10
  from prediction_market_agent_tooling.markets.data_models import (
10
11
  Bet,
@@ -196,3 +197,7 @@ class AgentMarket(BaseModel):
196
197
  if self.is_closed() or not self.has_liquidity():
197
198
  return False
198
199
  return True
200
+
201
+ @classmethod
202
+ def get_user_url(cls, keys: APIKeys) -> str:
203
+ raise NotImplementedError("Subclasses must implement this method")
@@ -11,6 +11,7 @@ from prediction_market_agent_tooling.markets.agent_market import (
11
11
  )
12
12
  from prediction_market_agent_tooling.markets.data_models import BetAmount, Currency
13
13
  from prediction_market_agent_tooling.markets.manifold.api import (
14
+ get_authenticated_user,
14
15
  get_manifold_binary_markets,
15
16
  place_bet,
16
17
  )
@@ -108,3 +109,7 @@ class ManifoldAgentMarket(AgentMarket):
108
109
  excluded_questions=excluded_questions,
109
110
  )
110
111
  ]
112
+
113
+ @classmethod
114
+ def get_user_url(cls, keys: APIKeys) -> str:
115
+ return get_authenticated_user(keys.manifold_api_key.get_secret_value()).url
@@ -422,7 +422,7 @@ class RealityQuestion(BaseModel):
422
422
  # And because all the contract methods so far needed bytes32 input, when asked for question id, `questionId` field was the correct one to use so far.
423
423
  id: str
424
424
  user: HexAddress
425
- historyHash: HexBytes
425
+ historyHash: HexBytes | None
426
426
  updatedTimestamp: datetime
427
427
  contentHash: HexBytes
428
428
  questionId: HexBytes
@@ -369,6 +369,10 @@ class OmenAgentMarket(AgentMarket):
369
369
 
370
370
  return positions
371
371
 
372
+ @classmethod
373
+ def get_user_url(cls, keys: APIKeys) -> str:
374
+ return f"https://gnosisscan.io/address/{keys.bet_from_address}"
375
+
372
376
 
373
377
  def pick_binary_market(
374
378
  sort_by: SortBy = SortBy.CLOSING_SOONEST, filter_by: FilterBy = FilterBy.OPEN
@@ -31,6 +31,7 @@ from prediction_market_agent_tooling.markets.omen.omen_subgraph_handler import (
31
31
  from prediction_market_agent_tooling.markets.polymarket.utils import (
32
32
  find_resolution_on_polymarket,
33
33
  )
34
+ from prediction_market_agent_tooling.tools.utils import check_not_none
34
35
  from prediction_market_agent_tooling.tools.web3_utils import ZERO_BYTES, xdai_to_wei
35
36
 
36
37
 
@@ -95,7 +96,12 @@ def claim_bonds_on_realitio_question(
95
96
  # TODO: See `if len(answers_objects) > 1` above.
96
97
  # This is from the original Olas implementation (https://github.com/kongzii/trader/blob/700af475a4538cc3d5d22caf9dec9e9d22d72af1/packages/valory/skills/market_manager_abci/graph_tooling/requests.py#L297),
97
98
  # but it's most probably wrong (see comment above).
98
- history_hashes.append(answers_objects[i + 1].question.historyHash)
99
+ history_hashes.append(
100
+ check_not_none(
101
+ answers_objects[i + 1].question.historyHash,
102
+ "Shouldn't be None here.",
103
+ )
104
+ )
99
105
 
100
106
  # last-to-first, the address of each answerer or commitment sender
101
107
  addresses.append(Web3.to_checksum_address(answer.question.user))
@@ -1,6 +1,8 @@
1
1
  import typing as t
2
2
 
3
3
  import requests
4
+ import tenacity
5
+ from loguru import logger
4
6
 
5
7
  from prediction_market_agent_tooling.markets.polymarket.data_models import (
6
8
  POLYMARKET_FALSE_OUTCOME,
@@ -18,6 +20,27 @@ POLYMARKET_API_BASE_URL = "https://clob.polymarket.com/"
18
20
  MARKETS_LIMIT = 100 # Polymarket will only return up to 100 markets
19
21
 
20
22
 
23
+ @tenacity.retry(
24
+ stop=tenacity.stop_after_attempt(5),
25
+ wait=tenacity.wait_chain(*[tenacity.wait_fixed(n) for n in range(1, 6)]),
26
+ after=lambda x: logger.debug(f"get_polymarkets failed, {x.attempt_number=}."),
27
+ )
28
+ def get_polymarkets(
29
+ limit: int,
30
+ with_rewards: bool = False,
31
+ next_cursor: str | None = None,
32
+ ) -> MarketsEndpointResponse:
33
+ url = (
34
+ f"{POLYMARKET_API_BASE_URL}/{'sampling-markets' if with_rewards else 'markets'}"
35
+ )
36
+ params: dict[str, str | int | float | None] = {
37
+ "limit": min(limit, MARKETS_LIMIT),
38
+ }
39
+ if next_cursor is not None:
40
+ params["next_cursor"] = next_cursor
41
+ return response_to_model(requests.get(url, params=params), MarketsEndpointResponse)
42
+
43
+
21
44
  def get_polymarket_binary_markets(
22
45
  limit: int,
23
46
  closed: bool | None = False,
@@ -28,17 +51,13 @@ def get_polymarket_binary_markets(
28
51
  """
29
52
  See https://learn.polymarket.com/trading-rewards for information about rewards.
30
53
  """
31
- url = (
32
- f"{POLYMARKET_API_BASE_URL}/{'sampling-markets' if with_rewards else 'markets'}"
33
- )
54
+
34
55
  all_markets: list[PolymarketMarketWithPrices] = []
35
- params: dict[str, str | int | float | None] = {
36
- "limit": min(limit, MARKETS_LIMIT),
37
- }
56
+ next_cursor: str | None = None
38
57
 
39
58
  while True:
40
- response = response_to_model(
41
- requests.get(url, params=params), MarketsEndpointResponse
59
+ response = get_polymarkets(
60
+ limit, with_rewards=with_rewards, next_cursor=next_cursor
42
61
  )
43
62
 
44
63
  for market in response.data:
@@ -81,12 +100,12 @@ def get_polymarket_binary_markets(
81
100
  if len(all_markets) >= limit:
82
101
  break
83
102
 
84
- if response.next_cursor == "LTE=":
103
+ next_cursor = response.next_cursor
104
+
105
+ if next_cursor == "LTE=":
85
106
  # 'LTE=' means the end.
86
107
  break
87
108
 
88
- params["next_cursor"] = response.next_cursor
89
-
90
109
  return all_markets[:limit]
91
110
 
92
111
 
@@ -32,8 +32,8 @@ class PolymarketMarket(BaseModel):
32
32
  active: bool
33
33
  closed: bool
34
34
  archived: bool
35
- minimum_order_size: str
36
- minimum_tick_size: str
35
+ minimum_order_size: str | float
36
+ minimum_tick_size: str | float
37
37
  condition_id: str
38
38
  question_id: str
39
39
  question: str
@@ -54,8 +54,8 @@ class PolymarketMarket(BaseModel):
54
54
  rewards: PolymarketRewards
55
55
  tokens: tuple[PolymarketToken, ...]
56
56
  is_50_50_outcome: bool
57
- categories: list[str]
58
- parent_categories: list[str]
57
+ categories: list[str] | None = None
58
+ parent_categories: list[str] | None = None
59
59
  accepting_orders: bool
60
60
 
61
61
  @property
@@ -208,6 +208,25 @@ class Category(BaseModel):
208
208
  slug: str
209
209
 
210
210
 
211
+ class Bid(BaseModel):
212
+ price: str
213
+ size: str
214
+
215
+
216
+ class Ask(BaseModel):
217
+ price: str
218
+ size: str
219
+
220
+
221
+ class MarketBidsAndAsks(BaseModel):
222
+ market: str
223
+ asset_id: str
224
+ hash: str
225
+ bids: list[Bid]
226
+ asks: list[Ask]
227
+ lastUpdated: int
228
+
229
+
211
230
  class PolymarketFullMarket(BaseModel):
212
231
  id: str
213
232
  ticker: str
@@ -231,7 +250,7 @@ class PolymarketFullMarket(BaseModel):
231
250
  liquidity: USDC | None
232
251
  volume: USDC | None
233
252
  volume24hr: USDC | None
234
- competitive: float
253
+ competitive: float | None
235
254
  openInterest: int | None
236
255
  sortBy: str | None
237
256
  createdAt: datetime
@@ -327,7 +346,12 @@ class PriceSide(BaseModel):
327
346
 
328
347
  class State(BaseModel):
329
348
  data: (
330
- PolymarketFullMarket | PriceSide | None
349
+ PolymarketFullMarket
350
+ | MarketBidsAndAsks
351
+ | PriceSide
352
+ | dict[str, MarketBidsAndAsks]
353
+ | dict[str, PriceSide]
354
+ | None
331
355
  ) # It's none if you go to the website and it says "Oops...we didn't forecast this".
332
356
  dataUpdateCount: int
333
357
  dataUpdatedAt: int
@@ -9,7 +9,11 @@ from prediction_market_agent_tooling.tools.google import search_google
9
9
  def find_resolution_on_polymarket(question: str) -> Resolution | None:
10
10
  full_market = find_full_polymarket(question)
11
11
  # TODO: Only main markets are supported right now, add logic for others if needed.
12
- return full_market.main_market.resolution if full_market else None
12
+ return (
13
+ full_market.main_market.resolution
14
+ if full_market and full_market.is_main_market
15
+ else None
16
+ )
13
17
 
14
18
 
15
19
  def find_full_polymarket(question: str) -> PolymarketFullMarket | None:
@@ -1,5 +1,6 @@
1
1
  from loguru import logger
2
2
 
3
+ from prediction_market_agent_tooling.config import APIKeys
3
4
  from prediction_market_agent_tooling.tools.cache import persistent_inmemory_cache
4
5
 
5
6
  # I tried to make it return a JSON, but it didn't work well in combo with asking it to do chain of thought.
@@ -44,7 +45,11 @@ def is_predictable_binary(
44
45
  logger.info("langchain not installed, skipping is_predictable_binary")
45
46
  return True
46
47
 
47
- llm = ChatOpenAI(model=engine, temperature=0.0)
48
+ llm = ChatOpenAI(
49
+ model=engine,
50
+ temperature=0.0,
51
+ api_key=APIKeys().openai_api_key.get_secret_value(),
52
+ )
48
53
 
49
54
  prompt = ChatPromptTemplate.from_template(template=prompt_template)
50
55
  messages = prompt.format_messages(question=question)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "prediction-market-agent-tooling"
3
- version = "0.28.0"
3
+ version = "0.30.0"
4
4
  description = "Tools to benchmark, deploy and monitor prediction market agents."
5
5
  authors = ["Gnosis"]
6
6
  readme = "README.md"