genlayer-test 0.1.0b5__py3-none-any.whl → 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {genlayer_test-0.1.0b5.dist-info → genlayer_test-0.1.1.dist-info}/METADATA +19 -2
  2. genlayer_test-0.1.1.dist-info/RECORD +52 -0
  3. {genlayer_test-0.1.0b5.dist-info → genlayer_test-0.1.1.dist-info}/WHEEL +1 -1
  4. gltest/artifacts/__init__.py +1 -1
  5. gltest/artifacts/contract.py +14 -5
  6. gltest/assertions.py +0 -1
  7. gltest/exceptions.py +9 -1
  8. gltest/glchain/account.py +1 -0
  9. gltest/glchain/contract.py +37 -5
  10. gltest/helpers/__init__.py +1 -1
  11. gltest/helpers/fixture_snapshot.py +9 -1
  12. tests/artifact/contracts/not_ic_contract.py +22 -0
  13. tests/artifact/test_contract_definition.py +92 -0
  14. tests/examples/contracts/football_prediction_market.py +97 -0
  15. tests/examples/contracts/intelligent_oracle.py +369 -0
  16. tests/examples/contracts/intelligent_oracle_factory.py +47 -0
  17. tests/examples/contracts/llm_erc20.py +69 -0
  18. tests/examples/contracts/log_indexer.py +67 -0
  19. tests/examples/contracts/multi_file_contract/__init__.py +20 -0
  20. tests/examples/contracts/multi_file_contract/other.py +14 -0
  21. tests/examples/contracts/multi_read_erc20.py +28 -0
  22. tests/examples/contracts/multi_tenant_storage.py +48 -0
  23. tests/examples/contracts/read_erc20.py +14 -0
  24. tests/examples/contracts/storage.py +22 -0
  25. tests/examples/contracts/user_storage.py +24 -0
  26. tests/examples/contracts/wizard_of_coin.py +56 -0
  27. tests/examples/tests/test_football_prediction_market.py +19 -0
  28. tests/examples/tests/test_intelligent_oracle_factory.py +127 -0
  29. tests/examples/tests/test_llm_erc20.py +41 -0
  30. tests/examples/tests/test_log_indexer.py +63 -0
  31. tests/examples/tests/test_multi_file_contract.py +15 -0
  32. tests/examples/tests/test_multi_file_contract_legacy.py +15 -0
  33. tests/examples/tests/test_multi_read_erc20.py +85 -0
  34. tests/examples/tests/test_multi_tenant_storage.py +58 -0
  35. tests/examples/tests/test_read_erc20.py +37 -0
  36. tests/examples/tests/test_storage.py +23 -0
  37. tests/examples/tests/test_storage_legacy.py +23 -0
  38. tests/examples/tests/test_user_storage.py +57 -0
  39. tests/examples/tests/test_wizard_of_coin.py +12 -0
  40. tests/plugin/conftest.py +1 -0
  41. genlayer_test-0.1.0b5.dist-info/RECORD +0 -24
  42. tests/conftest.py +0 -1
  43. {genlayer_test-0.1.0b5.dist-info → genlayer_test-0.1.1.dist-info}/entry_points.txt +0 -0
  44. {genlayer_test-0.1.0b5.dist-info → genlayer_test-0.1.1.dist-info}/licenses/LICENSE +0 -0
  45. {genlayer_test-0.1.0b5.dist-info → genlayer_test-0.1.1.dist-info}/top_level.txt +0 -0
  46. /tests/{test_plugin_hooks.py → plugin/test_plugin_hooks.py} +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genlayer-test
3
- Version: 0.1.0b5
3
+ Version: 0.1.1
4
4
  Summary: GenLayer Testing Suite
5
5
  Author: GenLayer
6
6
  License-Expression: MIT
@@ -16,7 +16,7 @@ Requires-Python: >=3.8
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Requires-Dist: pytest
19
- Requires-Dist: genlayer-py==0.1.0b1
19
+ Requires-Dist: genlayer-py==0.1.0
20
20
  Dynamic: license-file
21
21
 
22
22
  # GenLayer Testing Suite
@@ -128,6 +128,21 @@ $ gltest -v
128
128
  $ gltest --contracts-dir <path_to_contracts>
129
129
  ```
130
130
 
131
+ 6. Run tests with a custom RPC url
132
+ ```bash
133
+ $ gltest --rpc-url <custom_rpc_url>
134
+ ```
135
+
136
+ 6. Run tests with a default wait interval for waiting transaction receipts
137
+ ```bash
138
+ $ gltest --default-wait-interval <default_wait_interval>
139
+ ```
140
+
141
+ 6. Run tests with a default wait retries for waiting transaction receipts
142
+ ```bash
143
+ $ gltest --default-wait-retries <default_wait_retries>
144
+ ```
145
+
131
146
  ## 🚀 Key Features
132
147
 
133
148
  - **Pytest Integration** – Extends pytest to support intelligent contract testing, making it familiar and easy to adopt.
@@ -264,6 +279,8 @@ def test_write_methods():
264
279
  assert contract.get_storage() == "new_value"
265
280
  ```
266
281
 
282
+ For more example contracts, check out the [contracts directory](tests/examples/contracts) which contains various sample contracts demonstrating different features and use cases.
283
+
267
284
  ## 📝 Best Practices
268
285
 
269
286
  1. **Test Organization**
@@ -0,0 +1,52 @@
1
+ genlayer_test-0.1.1.dist-info/licenses/LICENSE,sha256=che_H4vE0QUx3HvWrAa1_jDEVInift0U6VO15-QqEls,1064
2
+ gltest/__init__.py,sha256=AK_YfRvwlhrOheOelUG8qIRG17on0-nFCF747dopg2w,332
3
+ gltest/assertions.py,sha256=O9pHt9aOxMVYk_C2fF2-qzT_xYMaK0YigR3HXeejmaU,590
4
+ gltest/exceptions.py,sha256=deJPmrTe5gF33qkkKF2IVJY7lc_knI7Ql3N7jZ8aLZs,510
5
+ gltest/plugin_config.py,sha256=8Z97RtEJ89OcRbki_oRuBBVct_q56BFmKvthan1y9Y4,840
6
+ gltest/plugin_hooks.py,sha256=py1rzIR9QSsFOt8SEePPL96e-8DeiPFxvcPZurRlExM,1436
7
+ gltest/types.py,sha256=BODmwTr2gAUEiO9FjiuTiWwuKvXgo4xZWstQWNUfnlw,156
8
+ gltest/artifacts/__init__.py,sha256=qiJN5F1cVh_3fmxZeDFznoABxAdLhLqBfUUKwqXqvgo,87
9
+ gltest/artifacts/contract.py,sha256=CBRfUTltKv2tPy--LcmVbP_4hbXYt9VrunvJlMzNd5s,3566
10
+ gltest/glchain/__init__.py,sha256=X-mEbREoAOe9K4n74C55gCiXH4wItzY5HTJcg3_F3mI,412
11
+ gltest/glchain/account.py,sha256=ZxYsfbtBXKVC5vV4pko3yyL6lhPljqIb68NgIgvInSc,403
12
+ gltest/glchain/client.py,sha256=q04LIQy5SCIrYZflZiTapfeQ-AaSTa0w369ehnVbJLM,532
13
+ gltest/glchain/contract.py,sha256=1pd4eAQlHXjnRF7hBvnoR-9f-HORUaYKVyV5P42io4o,8747
14
+ gltest/helpers/__init__.py,sha256=I7HiTu_H7_hP65zY6Wl02r-5eAMr2eZvqBVmusuQLX4,180
15
+ gltest/helpers/fixture_snapshot.py,sha256=DWLTsMbTnfhpv0_7_gkJpDKX4hJx-tlruX7x3FWL6UI,2073
16
+ gltest/helpers/take_snapshot.py,sha256=eXqEKXM2hcox3pLGIcNddobU8zXPQvD-Iwf87eHqW2s,1276
17
+ gltest_cli/main.py,sha256=Ti2-0Ev1x5_cM0D1UKqdgaDt80CDHEQGtdRne2qLm4M,53
18
+ tests/artifact/test_contract_definition.py,sha256=8X829MsNfEObtIMmotk6nRVLDEp5KfJE6zrAK4IPfCc,3323
19
+ tests/artifact/contracts/not_ic_contract.py,sha256=hQyGnYiiVceYdLI2WrvcFgPqzy1S4-YMb9FPhiHEGSA,510
20
+ tests/examples/contracts/football_prediction_market.py,sha256=kdouFijjeCdIJyaVJlgXcqbBAXecA9_YdhklSsIW-QM,3219
21
+ tests/examples/contracts/intelligent_oracle.py,sha256=WrNZWWoi1sz22Azt2EXgdWHDg5Ihca2pWUHrM9pVfQE,12319
22
+ tests/examples/contracts/intelligent_oracle_factory.py,sha256=ax496IZuDCA728rRcbjwTaM4Q4E-Y1jGkHsEcyf1cig,1490
23
+ tests/examples/contracts/llm_erc20.py,sha256=nfIs-7A79L46NgHQzWbPyEOUlzAlFLsf4K05acwKr_M,2523
24
+ tests/examples/contracts/log_indexer.py,sha256=VwMC8_Gy1Z1qjuy5GeEMyepjZ3Z5y7VAOrHMl5MrjxI,1852
25
+ tests/examples/contracts/multi_read_erc20.py,sha256=HsMJKGT9a9eZAO43Em7hCRfh1yyHDgcUbQ0gmOE1MXs,850
26
+ tests/examples/contracts/multi_tenant_storage.py,sha256=aGLPC76FegXdnIjMjeGsu3s3AbKK9dtV6t1d_KoI8rI,1897
27
+ tests/examples/contracts/read_erc20.py,sha256=kstiB93JHHajJe1GldzeawxnVYutjT8KE2d1bYTgggU,390
28
+ tests/examples/contracts/storage.py,sha256=GZHBXhjc94eEkdSO1UWgcop0fEo0hD57KZM0ds3pUFM,490
29
+ tests/examples/contracts/user_storage.py,sha256=j-RXxTIqb1dePYqP_pkeoCxxDq07VURryvzF_Q-sZmI,638
30
+ tests/examples/contracts/wizard_of_coin.py,sha256=BJ0Nv6N-JJP_Pk7YUSXPPRxX5_mDRBDlfL6nabeaoyA,1606
31
+ tests/examples/contracts/multi_file_contract/__init__.py,sha256=8O3BvoUrLSmc4uTf2jm7MyrmcaiGD0w8wPwotdAqZHQ,485
32
+ tests/examples/contracts/multi_file_contract/other.py,sha256=jHDtjUL3eAUgE6yOYKFw_RfAH7kIwk8CvxUjbWHNruk,236
33
+ tests/examples/tests/test_football_prediction_market.py,sha256=wFu024sq3IURLL1zyLyO_G1sRCjPTV7iImi87__dZ4Y,657
34
+ tests/examples/tests/test_intelligent_oracle_factory.py,sha256=Nw7jO9bjD79AETT2QQl0Vun-yxSAAuqGSdkQn2Y3WUw,5377
35
+ tests/examples/tests/test_llm_erc20.py,sha256=yL_5bbH2VC7jL3E6dDvSI6PfZ36bPtA4OxoysZpuLFc,1390
36
+ tests/examples/tests/test_log_indexer.py,sha256=Km44SiA8dlA4WBqwugXVBCQUlODdf1dB4p4nt24HG9k,2649
37
+ tests/examples/tests/test_multi_file_contract.py,sha256=pWmK6lcZrSAnDH09Z6Q-cXs8V6VGFhHkvgThvJKEB4U,512
38
+ tests/examples/tests/test_multi_file_contract_legacy.py,sha256=Jx_u0rDrQJspQgFo1KUddcFgTcOhcE-YLuLgk3tKrCA,527
39
+ tests/examples/tests/test_multi_read_erc20.py,sha256=Q3AKK7OZyTKRrG-tXmkPkoQOzQqVVDnFEWKDVVNVQLI,3062
40
+ tests/examples/tests/test_multi_tenant_storage.py,sha256=XNR1AUpxkzXlRv_ltdgAF-HUkpAvWqIQ7Fb93zEeR2o,2376
41
+ tests/examples/tests/test_read_erc20.py,sha256=_dXwdZoUTSMKwPhEmU3N2X3wNu2ke9ob0L3JKEyNjdE,1198
42
+ tests/examples/tests/test_storage.py,sha256=FmA-pJohMBHlNFVzLlY3-asnq0kV33E5SRDCM-lWzoQ,664
43
+ tests/examples/tests/test_storage_legacy.py,sha256=RNVnD0G9ilb4I2s0CPAAgJEuKUgEkkbItuesOfmv-pg,677
44
+ tests/examples/tests/test_user_storage.py,sha256=QEgt2p22LAyzBnBb0YW4BWa_Jasrt15vrr1GuxXqqbI,2180
45
+ tests/examples/tests/test_wizard_of_coin.py,sha256=aUDeV5w0XONMMS71Vzw80lHfcSM0z8RKPJSXAuDwRto,392
46
+ tests/plugin/conftest.py,sha256=RKdoE5_zcMimeojAoA_GSFI9du4pMzMi1vZ1njtfoAs,28
47
+ tests/plugin/test_plugin_hooks.py,sha256=FQOrkhoXLinq0sjvoYjr63Oqg-ZVPcNFeUrK4bqrn4E,2020
48
+ genlayer_test-0.1.1.dist-info/METADATA,sha256=SLlBr5OZZWmgBKAfkz889L-k7mMYX92PFyiCjK67oVQ,13471
49
+ genlayer_test-0.1.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
50
+ genlayer_test-0.1.1.dist-info/entry_points.txt,sha256=rXhrPVq2IhVsd4uWzxzwCTx7jA1KcQIVNxDCUuxq4f8,89
51
+ genlayer_test-0.1.1.dist-info/top_level.txt,sha256=-qiGZxTRBytujzgVcKpxjvQ-WNeUDjXa59ceGMwMpko,24
52
+ genlayer_test-0.1.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,3 +1,3 @@
1
1
  from .contract import find_contract_definition
2
2
 
3
- __all__ = ["find_contract_definition"]
3
+ __all__ = ["find_contract_definition"]
@@ -20,7 +20,9 @@ class ContractDefinition:
20
20
 
21
21
  def search_path_by_class_name(contracts_dir: Path, contract_name: str) -> Path:
22
22
  """Search for a file by class name in the contracts directory."""
23
- for file_path in contracts_dir.rglob("*.gpy"):
23
+ for file_path in contracts_dir.rglob("*"):
24
+ if not file_path.suffix in [".gpy", ".py"]:
25
+ continue
24
26
  try:
25
27
  # Read the file content
26
28
  with open(file_path, "r") as f:
@@ -30,8 +32,15 @@ def search_path_by_class_name(contracts_dir: Path, contract_name: str) -> Path:
30
32
  # Search for class definitions
31
33
  for node in ast.walk(tree):
32
34
  if isinstance(node, ast.ClassDef) and node.name == contract_name:
33
- # Found the contract class
34
- return file_path
35
+ # Check if the class directly inherits from gl.Contract
36
+ for base in node.bases:
37
+ if isinstance(base, ast.Attribute):
38
+ if (
39
+ isinstance(base.value, ast.Name)
40
+ and base.value.id == "gl"
41
+ and base.attr == "Contract"
42
+ ):
43
+ return file_path
35
44
  except Exception as e:
36
45
  raise ValueError(f"Error reading file {file_path}: {e}")
37
46
  raise FileNotFoundError(f"Contract {contract_name} not found at: {contracts_dir}")
@@ -53,7 +62,7 @@ def compute_contract_code(
53
62
  with zipfile.ZipFile(buffer, mode="w") as zip:
54
63
  zip.write(main_file_path, "contract/__init__.py")
55
64
  for file_path in main_file_dir.rglob("*"):
56
- if file_path.name in ["runner.json", "__init__.gpy"]:
65
+ if file_path.name in ["runner.json", "__init__.py"]:
57
66
  continue
58
67
  rel_path = file_path.relative_to(main_file_dir)
59
68
  zip.write(file_path, f"contract/{rel_path}")
@@ -72,7 +81,7 @@ def find_contract_definition(contract_name: str) -> Optional[ContractDefinition]
72
81
  main_file_path = search_path_by_class_name(contracts_dir, contract_name)
73
82
  main_file_dir = main_file_path.parent
74
83
  runner_file_path = None
75
- if main_file_path.name == "__init__.gpy":
84
+ if main_file_path.name in ["__init__.py", "__init__.gpy"]:
76
85
  # Likely a multifile contract
77
86
  runner_file_path = main_file_dir.joinpath("runner.json")
78
87
  if not runner_file_path.exists():
gltest/assertions.py CHANGED
@@ -14,4 +14,3 @@ def tx_execution_succeeded(result: GenLayerTransaction) -> bool:
14
14
 
15
15
  def tx_execution_failed(result: GenLayerTransaction) -> bool:
16
16
  return not tx_execution_succeeded(result)
17
-
gltest/exceptions.py CHANGED
@@ -2,19 +2,27 @@ class DeploymentError(Exception):
2
2
  """Raised when a contract deployment fails."""
3
3
 
4
4
  pass
5
+
6
+
5
7
  class FixtureSnapshotError(Exception):
6
8
  """Raised when there's an error restoring a snapshot."""
9
+
7
10
  pass
8
11
 
12
+
9
13
  class FixtureAnonymousFunctionError(Exception):
10
14
  """Raised when a fixture is an anonymous function."""
15
+
11
16
  pass
12
17
 
18
+
13
19
  class InvalidSnapshotError(Exception):
14
20
  """Raised when a snapshot is invalid."""
21
+
15
22
  pass
16
23
 
24
+
17
25
  class HelperError(Exception):
18
26
  """Raised when a helper function fails."""
19
- pass
20
27
 
28
+ pass
gltest/glchain/account.py CHANGED
@@ -10,6 +10,7 @@ def create_accounts(n_accounts: int):
10
10
  accounts.append(create_account())
11
11
  return accounts
12
12
 
13
+
13
14
  # Accounts for testing
14
15
  accounts = create_accounts(n_accounts=10)
15
16
 
@@ -1,10 +1,15 @@
1
+ from eth_typing import (
2
+ Address,
3
+ ChecksumAddress,
4
+ )
5
+ from eth_account.signers.local import LocalAccount
6
+ from typing import Union
1
7
  from dataclasses import dataclass
2
8
  from gltest.artifacts import find_contract_definition
3
9
  from gltest.assertions import tx_execution_failed
4
10
  from gltest.exceptions import DeploymentError
5
11
  from .client import get_gl_client
6
12
  from gltest.types import CalldataEncodable, GenLayerTransaction, TransactionStatus
7
- from eth_account.signers.local import LocalAccount
8
13
  from typing import List, Any, Type, Optional, Dict, Callable
9
14
  import types
10
15
  from gltest.plugin_config import get_default_wait_interval, get_default_wait_retries
@@ -89,14 +94,18 @@ class Contract:
89
94
  consensus_max_rotations: Optional[int] = None,
90
95
  leader_only: bool = False,
91
96
  wait_transaction_status: TransactionStatus = TransactionStatus.FINALIZED,
92
- wait_interval: int = get_default_wait_interval(),
93
- wait_retries: int = get_default_wait_retries(),
97
+ wait_interval: Optional[int] = None,
98
+ wait_retries: Optional[int] = None,
94
99
  wait_triggered_transactions: bool = True,
95
100
  wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
96
101
  ) -> GenLayerTransaction:
97
102
  """
98
103
  Wrapper to the contract write method.
99
104
  """
105
+ if wait_interval is None:
106
+ wait_interval = get_default_wait_interval()
107
+ if wait_retries is None:
108
+ wait_retries = get_default_wait_retries()
100
109
  client = get_gl_client()
101
110
  tx_hash = client.write_contract(
102
111
  address=self.address,
@@ -152,19 +161,42 @@ class ContractFactory:
152
161
  contract_name=contract_name, contract_code=contract_info.contract_code
153
162
  )
154
163
 
164
+ def build_contract(
165
+ self,
166
+ contract_address: Union[Address, ChecksumAddress],
167
+ account: Optional[LocalAccount] = None,
168
+ ) -> Contract:
169
+ """
170
+ Build contract from address
171
+ """
172
+ client = get_gl_client()
173
+ try:
174
+ schema = client.get_contract_schema(address=contract_address)
175
+ return Contract.new(
176
+ address=contract_address, schema=schema, account=account
177
+ )
178
+ except Exception as e:
179
+ raise ValueError(
180
+ f"Failed to build contract {self.contract_name}: {str(e)}"
181
+ ) from e
182
+
155
183
  def deploy(
156
184
  self,
157
185
  args: List[Any] = [],
158
186
  account: Optional[LocalAccount] = None,
159
187
  consensus_max_rotations: Optional[int] = None,
160
188
  leader_only: bool = False,
161
- wait_interval: int = get_default_wait_interval(),
162
- wait_retries: int = get_default_wait_retries(),
189
+ wait_interval: Optional[int] = None,
190
+ wait_retries: Optional[int] = None,
163
191
  wait_transaction_status: TransactionStatus = TransactionStatus.FINALIZED,
164
192
  ) -> Contract:
165
193
  """
166
194
  Deploy the contract
167
195
  """
196
+ if wait_interval is None:
197
+ wait_interval = get_default_wait_interval()
198
+ if wait_retries is None:
199
+ wait_retries = get_default_wait_retries()
168
200
  client = get_gl_client()
169
201
  try:
170
202
  tx_hash = client.deploy_contract(
@@ -5,4 +5,4 @@ __all__ = [
5
5
  "take_snapshot",
6
6
  "load_fixture",
7
7
  "clear_snapshots",
8
- ]
8
+ ]
@@ -1,12 +1,15 @@
1
1
  from typing import TypeVar, Callable, List, Any
2
2
  from dataclasses import dataclass
3
+ from urllib.parse import urlparse
3
4
  from .take_snapshot import SnapshotRestorer, take_snapshot
4
5
  from gltest.exceptions import (
5
6
  FixtureSnapshotError,
6
7
  InvalidSnapshotError,
7
8
  FixtureAnonymousFunctionError,
8
9
  )
10
+ from gltest.plugin_config import get_rpc_url
9
11
 
12
+ SUPPORTED_RPC_DOMAINS = ["localhost", "127.0.0.1"]
10
13
 
11
14
  T = TypeVar("T")
12
15
 
@@ -31,6 +34,11 @@ def load_fixture(fixture: Callable[[], T]) -> T:
31
34
  if fixture.__name__ == "<lambda>":
32
35
  raise FixtureAnonymousFunctionError("Fixtures must be named functions")
33
36
 
37
+ rpc_url = get_rpc_url()
38
+ domain = urlparse(rpc_url).netloc.split(":")[0] # Extract domain without port
39
+ if domain not in SUPPORTED_RPC_DOMAINS:
40
+ return fixture()
41
+
34
42
  # Find existing snapshot for this fixture
35
43
  global _snapshots
36
44
  snapshot = next((s for s in _snapshots if s.fixture == fixture), None)
@@ -38,8 +46,8 @@ def load_fixture(fixture: Callable[[], T]) -> T:
38
46
  if snapshot is not None:
39
47
  try:
40
48
  snapshot.restorer.restore()
49
+
41
50
  # Remove snapshots that were taken after this one
42
-
43
51
  _snapshots = [
44
52
  s
45
53
  for s in _snapshots
@@ -0,0 +1,22 @@
1
+ # { "Depends": "py-genlayer:test" }
2
+
3
+ from genlayer import *
4
+
5
+
6
+ # contract class that is not an IC contract
7
+ class NotICContract:
8
+ storage: str
9
+
10
+ # constructor
11
+ def __init__(self, initial_storage: str):
12
+ self.storage = initial_storage
13
+
14
+ # read methods must be annotated with view
15
+ @gl.public.view
16
+ def get_storage(self) -> str:
17
+ return self.storage
18
+
19
+ # write method
20
+ @gl.public.write
21
+ def update_storage(self, new_storage: str) -> None:
22
+ self.storage = new_storage
@@ -0,0 +1,92 @@
1
+ import pytest
2
+ from gltest.artifacts.contract import (
3
+ find_contract_definition,
4
+ compute_contract_code,
5
+ )
6
+ from gltest.plugin_config import set_contracts_dir
7
+ from pathlib import Path
8
+
9
+
10
+ def test_single_file():
11
+ set_contracts_dir(".")
12
+ contract_definition = find_contract_definition("PredictionMarket")
13
+
14
+ assert contract_definition.contract_name == "PredictionMarket"
15
+
16
+ # Assert complete contract definition
17
+ expected_main_file_path = Path("examples/contracts/football_prediction_market.py")
18
+ expected_runner_file_path = None
19
+ contract_code = compute_contract_code(
20
+ expected_main_file_path, expected_runner_file_path
21
+ )
22
+ assert contract_definition.contract_code == contract_code
23
+ assert (
24
+ str(contract_definition.main_file_path)
25
+ == "examples/contracts/football_prediction_market.py"
26
+ )
27
+ assert contract_definition.runner_file_path is None
28
+
29
+
30
+ def test_multiple_files():
31
+ set_contracts_dir(".")
32
+ contract_definition = find_contract_definition("MultiFileContract")
33
+
34
+ assert contract_definition.contract_name == "MultiFileContract"
35
+
36
+ # Assert complete contract definition
37
+ expected_main_file_path = Path("examples/contracts/multi_file_contract/__init__.py")
38
+ expected_runner_file_path = Path(
39
+ "examples/contracts/multi_file_contract/runner.json"
40
+ )
41
+ assert contract_definition.main_file_path == expected_main_file_path
42
+ assert contract_definition.runner_file_path == expected_runner_file_path
43
+ contract_code = compute_contract_code(
44
+ expected_main_file_path, expected_runner_file_path
45
+ )
46
+ assert contract_definition.contract_code == contract_code
47
+
48
+
49
+ def test_single_file_legacy():
50
+ set_contracts_dir(".")
51
+ contract_definition = find_contract_definition("StorageLegacy")
52
+
53
+ # Assert complete contract definition
54
+ assert contract_definition.contract_name == "StorageLegacy"
55
+ expected_main_file_path = Path("examples/contracts/storage_legacy.gpy")
56
+ expected_runner_file_path = None
57
+ contract_code = compute_contract_code(
58
+ expected_main_file_path, expected_runner_file_path
59
+ )
60
+ assert contract_definition.contract_code == contract_code
61
+ assert (
62
+ str(contract_definition.main_file_path)
63
+ == "examples/contracts/storage_legacy.gpy"
64
+ )
65
+ assert contract_definition.runner_file_path is None
66
+
67
+
68
+ def test_multiple_files_legacy():
69
+ set_contracts_dir(".")
70
+ contract_definition = find_contract_definition("MultiFileContractLegacy")
71
+
72
+ # Assert complete contract definition
73
+ assert contract_definition.contract_name == "MultiFileContractLegacy"
74
+ expected_main_file_path = Path(
75
+ "examples/contracts/multi_file_contract_legacy/__init__.gpy"
76
+ )
77
+ expected_runner_file_path = Path(
78
+ "examples/contracts/multi_file_contract_legacy/runner.json"
79
+ )
80
+ assert contract_definition.main_file_path == expected_main_file_path
81
+ assert contract_definition.runner_file_path == expected_runner_file_path
82
+ contract_code = compute_contract_code(
83
+ expected_main_file_path, expected_runner_file_path
84
+ )
85
+ assert contract_definition.contract_code == contract_code
86
+
87
+
88
+ def test_class_is_not_intelligent_contract():
89
+ set_contracts_dir(".")
90
+
91
+ with pytest.raises(FileNotFoundError):
92
+ _ = find_contract_definition("NotICContract")
@@ -0,0 +1,97 @@
1
+ # { "Depends": "py-genlayer:test" }
2
+
3
+ from genlayer import *
4
+
5
+ import json
6
+ import typing
7
+
8
+
9
+ class PredictionMarket(gl.Contract):
10
+ has_resolved: bool
11
+ team1: str
12
+ team2: str
13
+ resolution_url: str
14
+ winner: u256
15
+ score: str
16
+
17
+ def __init__(self, game_date: str, team1: str, team2: str):
18
+ """
19
+ Initializes a new instance of the prediction market with the specified game date and teams.
20
+
21
+ Args:
22
+ game_date (str): The date of the game in the format 'YYYY-MM-DD'.
23
+ team1 (str): The name of the first team.
24
+ team2 (str): The name of the second team.
25
+
26
+ Attributes:
27
+ has_resolved (bool): Indicates whether the game's resolution has been processed. Default is False.
28
+ game_date (str): The date of the game.
29
+ resolution_url (str): The URL to the game's resolution on BBC Sport.
30
+ team1 (str): The name of the first team.
31
+ team2 (str): The name of the second team.
32
+ """
33
+ self.has_resolved = False
34
+ self.resolution_url = (
35
+ "https://www.bbc.com/sport/football/scores-fixtures/" + game_date
36
+ )
37
+ self.team1 = team1
38
+ self.team2 = team2
39
+ self.winner = 0
40
+ self.score = ""
41
+
42
+ @gl.public.write
43
+ def resolve(self) -> typing.Any:
44
+
45
+ if self.has_resolved:
46
+ return "Already resolved"
47
+
48
+ market_resolution_url = self.resolution_url
49
+ team1 = self.team1
50
+ team2 = self.team2
51
+
52
+ def get_match_result() -> str:
53
+ web_data = gl.get_webpage(market_resolution_url, mode="text")
54
+ print(web_data)
55
+
56
+ task = f"""
57
+ In the following web page, find the winning team in a matchup between the following teams:
58
+ Team 1: {team1}
59
+ Team 2: {team2}
60
+
61
+ Web page content:
62
+ {web_data}
63
+ End of web page data.
64
+
65
+ If it says "Kick off [time]" between the names of the two teams, it means the game hasn't started yet.
66
+ If you fail to extract the score, assume the game is not resolved yet.
67
+
68
+ Respond with the following JSON format:
69
+ {{
70
+ "score": str, // The score with numbers only, e.g, "1:2", or "-" if the game is not resolved yet
71
+ "winner": int, // The number of the winning team, 0 for draw, or -1 if the game is not yet finished
72
+ }}
73
+ It is mandatory that you respond only using the JSON format above,
74
+ nothing else. Don't include any other words or characters,
75
+ your output must be only JSON without any formatting prefix or suffix.
76
+ This result should be perfectly parsable by a JSON parser without errors.
77
+ """
78
+ result = gl.exec_prompt(task).replace("```json", "").replace("```", "")
79
+ print(result)
80
+ return json.dumps(json.loads(result), sort_keys=True)
81
+
82
+ result_json = json.loads(gl.eq_principle_strict_eq(get_match_result))
83
+
84
+ if result_json["winner"] > -1:
85
+ self.has_resolved = True
86
+ self.winner = result_json["winner"]
87
+ self.score = result_json["score"]
88
+
89
+ return result_json
90
+
91
+ @gl.public.view
92
+ def get_resolution_data(self) -> dict[str, typing.Any]:
93
+ return {
94
+ "winner": self.winner,
95
+ "score": self.score,
96
+ "has_resolved": self.has_resolved,
97
+ }