genlayer-test 0.1.0b6__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.
- {genlayer_test-0.1.0b6.dist-info → genlayer_test-0.1.1.dist-info}/METADATA +19 -2
- genlayer_test-0.1.1.dist-info/RECORD +52 -0
- {genlayer_test-0.1.0b6.dist-info → genlayer_test-0.1.1.dist-info}/WHEEL +1 -1
- gltest/artifacts/__init__.py +1 -1
- gltest/artifacts/contract.py +14 -5
- gltest/assertions.py +0 -1
- gltest/exceptions.py +9 -1
- gltest/glchain/account.py +1 -0
- gltest/helpers/__init__.py +1 -1
- gltest/helpers/fixture_snapshot.py +9 -1
- tests/artifact/contracts/not_ic_contract.py +22 -0
- tests/artifact/test_contract_definition.py +92 -0
- tests/examples/contracts/football_prediction_market.py +97 -0
- tests/examples/contracts/intelligent_oracle.py +369 -0
- tests/examples/contracts/intelligent_oracle_factory.py +47 -0
- tests/examples/contracts/llm_erc20.py +69 -0
- tests/examples/contracts/log_indexer.py +67 -0
- tests/examples/contracts/multi_file_contract/__init__.py +20 -0
- tests/examples/contracts/multi_file_contract/other.py +14 -0
- tests/examples/contracts/multi_read_erc20.py +28 -0
- tests/examples/contracts/multi_tenant_storage.py +48 -0
- tests/examples/contracts/read_erc20.py +14 -0
- tests/examples/contracts/storage.py +22 -0
- tests/examples/contracts/user_storage.py +24 -0
- tests/examples/contracts/wizard_of_coin.py +56 -0
- tests/examples/tests/test_football_prediction_market.py +19 -0
- tests/examples/tests/test_intelligent_oracle_factory.py +127 -0
- tests/examples/tests/test_llm_erc20.py +41 -0
- tests/examples/tests/test_log_indexer.py +63 -0
- tests/examples/tests/test_multi_file_contract.py +15 -0
- tests/examples/tests/test_multi_file_contract_legacy.py +15 -0
- tests/examples/tests/test_multi_read_erc20.py +85 -0
- tests/examples/tests/test_multi_tenant_storage.py +58 -0
- tests/examples/tests/test_read_erc20.py +37 -0
- tests/examples/tests/test_storage.py +23 -0
- tests/examples/tests/test_storage_legacy.py +23 -0
- tests/examples/tests/test_user_storage.py +57 -0
- tests/examples/tests/test_wizard_of_coin.py +12 -0
- tests/plugin/conftest.py +1 -0
- genlayer_test-0.1.0b6.dist-info/RECORD +0 -24
- tests/conftest.py +0 -1
- {genlayer_test-0.1.0b6.dist-info → genlayer_test-0.1.1.dist-info}/entry_points.txt +0 -0
- {genlayer_test-0.1.0b6.dist-info → genlayer_test-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {genlayer_test-0.1.0b6.dist-info → genlayer_test-0.1.1.dist-info}/top_level.txt +0 -0
- /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.
|
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.
|
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,,
|
gltest/artifacts/__init__.py
CHANGED
gltest/artifacts/contract.py
CHANGED
@@ -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("
|
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
|
-
#
|
34
|
-
|
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__.
|
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
|
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
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
gltest/helpers/__init__.py
CHANGED
@@ -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
|
+
}
|