genlayer-test 0.4.1__py3-none-any.whl → 2.0.0__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 (44) hide show
  1. {genlayer_test-0.4.1.dist-info → genlayer_test-2.0.0.dist-info}/METADATA +75 -14
  2. genlayer_test-2.0.0.dist-info/RECORD +76 -0
  3. gltest/__init__.py +7 -6
  4. gltest/{glchain/client.py → clients.py} +1 -1
  5. gltest/contracts/__init__.py +4 -0
  6. gltest/contracts/contract.py +197 -0
  7. gltest/{glchain/contract.py → contracts/contract_factory.py} +22 -137
  8. gltest/contracts/contract_functions.py +59 -0
  9. gltest/contracts/method_stats.py +163 -0
  10. gltest/contracts/stats_collector.py +259 -0
  11. gltest/contracts/utils.py +12 -0
  12. gltest/fixtures.py +2 -6
  13. gltest/helpers/take_snapshot.py +1 -1
  14. gltest_cli/config/constants.py +1 -0
  15. gltest_cli/config/plugin.py +53 -0
  16. gltest_cli/config/pytest_context.py +9 -0
  17. gltest_cli/config/types.py +41 -0
  18. gltest_cli/config/user.py +21 -8
  19. tests/examples/contracts/football_prediction_market.py +1 -1
  20. tests/examples/tests/test_football_prediction_market.py +2 -2
  21. tests/examples/tests/test_intelligent_oracle_factory.py +6 -6
  22. tests/examples/tests/test_llm_erc20.py +5 -5
  23. tests/examples/tests/test_llm_erc20_analyze.py +50 -0
  24. tests/examples/tests/test_log_indexer.py +23 -11
  25. tests/examples/tests/test_multi_file_contract.py +2 -2
  26. tests/examples/tests/test_multi_file_contract_legacy.py +2 -2
  27. tests/examples/tests/test_multi_read_erc20.py +14 -12
  28. tests/examples/tests/test_multi_tenant_storage.py +11 -7
  29. tests/examples/tests/test_read_erc20.py +1 -1
  30. tests/examples/tests/test_storage.py +4 -4
  31. tests/examples/tests/test_storage_legacy.py +5 -3
  32. tests/examples/tests/test_user_storage.py +20 -10
  33. tests/examples/tests/test_wizard_of_coin.py +1 -1
  34. tests/gltest_cli/config/test_config_integration.py +432 -0
  35. tests/gltest_cli/config/test_general_config.py +406 -0
  36. tests/gltest_cli/config/test_plugin.py +167 -0
  37. tests/gltest_cli/config/test_user.py +61 -1
  38. genlayer_test-0.4.1.dist-info/RECORD +0 -67
  39. gltest/glchain/__init__.py +0 -16
  40. {genlayer_test-0.4.1.dist-info → genlayer_test-2.0.0.dist-info}/WHEEL +0 -0
  41. {genlayer_test-0.4.1.dist-info → genlayer_test-2.0.0.dist-info}/entry_points.txt +0 -0
  42. {genlayer_test-0.4.1.dist-info → genlayer_test-2.0.0.dist-info}/licenses/LICENSE +0 -0
  43. {genlayer_test-0.4.1.dist-info → genlayer_test-2.0.0.dist-info}/top_level.txt +0 -0
  44. /gltest/{glchain/account.py → accounts.py} +0 -0
@@ -0,0 +1,12 @@
1
+ def safe_filename(filename: str) -> str:
2
+ """
3
+ Replace problematic characters in filename.
4
+ """
5
+ return (
6
+ filename.replace("/", "_")
7
+ .replace("\\", "_")
8
+ .replace(":", "_")
9
+ .replace("-", "_")
10
+ .replace(" ", "_")
11
+ .replace(".py", "")
12
+ )
gltest/fixtures.py CHANGED
@@ -4,12 +4,8 @@ These fixtures can be imported and used in test files.
4
4
  """
5
5
 
6
6
  import pytest
7
- from gltest.glchain import (
8
- get_gl_client,
9
- get_accounts,
10
- get_default_account,
11
- get_gl_provider,
12
- )
7
+ from gltest.clients import get_gl_client, get_gl_provider
8
+ from gltest.accounts import get_accounts, get_default_account
13
9
  from gltest_cli.config.general import get_general_config
14
10
 
15
11
 
@@ -1,4 +1,4 @@
1
- from gltest.glchain import get_gl_provider
1
+ from gltest.clients import get_gl_provider
2
2
  from dataclasses import dataclass
3
3
  from typing import Callable
4
4
  from gltest.exceptions import HelperError, InvalidSnapshotError
@@ -7,4 +7,5 @@ DEFAULT_NETWORK = "localnet"
7
7
  DEFAULT_RPC_URL = SIMULATOR_JSON_RPC_URL
8
8
  DEFAULT_ENVIRONMENT = ".env"
9
9
  DEFAULT_CONTRACTS_DIR = Path("contracts")
10
+ DEFAULT_ARTIFACTS_DIR = Path("artifacts")
10
11
  DEFAULT_NETWORK_ID = 61999
@@ -1,4 +1,5 @@
1
1
  from pathlib import Path
2
+ import shutil
2
3
  from gltest_cli.logging import logger
3
4
  from gltest_cli.config.user import (
4
5
  user_config_exists,
@@ -9,6 +10,7 @@ from gltest_cli.config.general import (
9
10
  get_general_config,
10
11
  )
11
12
  from gltest_cli.config.types import PluginConfig
13
+ from gltest_cli.config.pytest_context import _pytest_context
12
14
 
13
15
 
14
16
  def pytest_addoption(parser):
@@ -20,6 +22,13 @@ def pytest_addoption(parser):
20
22
  help="Path to directory containing contract files",
21
23
  )
22
24
 
25
+ group.addoption(
26
+ "--artifacts-dir",
27
+ action="store",
28
+ default=None,
29
+ help="Path to directory for storing contract artifacts",
30
+ )
31
+
23
32
  group.addoption(
24
33
  "--default-wait-interval",
25
34
  action="store",
@@ -55,6 +64,13 @@ def pytest_addoption(parser):
55
64
  help="Test with mocks",
56
65
  )
57
66
 
67
+ group.addoption(
68
+ "--leader-only",
69
+ action="store_true",
70
+ default=False,
71
+ help="Run contracts in leader-only mode",
72
+ )
73
+
58
74
 
59
75
  def pytest_configure(config):
60
76
  general_config = get_general_config()
@@ -76,27 +92,45 @@ def pytest_configure(config):
76
92
 
77
93
  # Handle plugin config from command line
78
94
  contracts_dir = config.getoption("--contracts-dir")
95
+ artifacts_dir = config.getoption("--artifacts-dir")
79
96
  default_wait_interval = config.getoption("--default-wait-interval")
80
97
  default_wait_retries = config.getoption("--default-wait-retries")
81
98
  rpc_url = config.getoption("--rpc-url")
82
99
  network = config.getoption("--network")
83
100
  test_with_mocks = config.getoption("--test-with-mocks")
101
+ leader_only = config.getoption("--leader-only")
84
102
 
85
103
  plugin_config = PluginConfig()
86
104
  plugin_config.contracts_dir = (
87
105
  Path(contracts_dir) if contracts_dir is not None else None
88
106
  )
107
+ plugin_config.artifacts_dir = (
108
+ Path(artifacts_dir) if artifacts_dir is not None else None
109
+ )
89
110
  plugin_config.default_wait_interval = int(default_wait_interval)
90
111
  plugin_config.default_wait_retries = int(default_wait_retries)
91
112
  plugin_config.rpc_url = rpc_url
92
113
  plugin_config.network_name = network
93
114
  plugin_config.test_with_mocks = test_with_mocks
115
+ plugin_config.leader_only = leader_only
94
116
 
95
117
  general_config.plugin_config = plugin_config
96
118
 
97
119
 
98
120
  def pytest_sessionstart(session):
99
121
  general_config = get_general_config()
122
+
123
+ artifacts_dir = general_config.get_artifacts_dir()
124
+ if artifacts_dir and artifacts_dir.exists():
125
+ logger.info(f"Clearing artifacts directory: {artifacts_dir}")
126
+ try:
127
+ shutil.rmtree(artifacts_dir)
128
+ artifacts_dir.mkdir(parents=True, exist_ok=True)
129
+ except Exception as e:
130
+ logger.warning(f"Failed to clear artifacts directory: {e}")
131
+ elif artifacts_dir:
132
+ artifacts_dir.mkdir(parents=True, exist_ok=True)
133
+
100
134
  logger.info("Using the following configuration:")
101
135
  logger.info(f" RPC URL: {general_config.get_rpc_url()}")
102
136
  logger.info(f" Selected Network: {general_config.get_network_name()}")
@@ -104,6 +138,7 @@ def pytest_sessionstart(session):
104
138
  f" Available networks: {list(general_config.user_config.networks.keys())}"
105
139
  )
106
140
  logger.info(f" Contracts directory: {general_config.get_contracts_dir()}")
141
+ logger.info(f" Artifacts directory: {general_config.get_artifacts_dir()}")
107
142
  logger.info(f" Environment: {general_config.user_config.environment}")
108
143
  logger.info(
109
144
  f" Default wait interval: {general_config.get_default_wait_interval()} ms"
@@ -111,5 +146,23 @@ def pytest_sessionstart(session):
111
146
  logger.info(f" Default wait retries: {general_config.get_default_wait_retries()}")
112
147
  logger.info(f" Test with mocks: {general_config.get_test_with_mocks()}")
113
148
 
149
+ if general_config.get_leader_only() and not general_config.check_studio_based_rpc():
150
+ logger.warning(
151
+ "Leader only mode: True (enabled on non-studio network - will have no effect)"
152
+ )
153
+ else:
154
+ logger.info(f" Leader only mode: {general_config.get_leader_only()}")
155
+
156
+
157
+ def pytest_runtest_setup(item):
158
+ _pytest_context.current_item = item
159
+
160
+
161
+ def pytest_runtest_teardown(item):
162
+ try:
163
+ del _pytest_context.current_item
164
+ except AttributeError:
165
+ pass
166
+
114
167
 
115
168
  pytest_plugins = ["gltest.fixtures"]
@@ -0,0 +1,9 @@
1
+ from typing import Optional
2
+ import threading
3
+
4
+ _pytest_context = threading.local()
5
+
6
+
7
+ def get_current_test_nodeid() -> Optional[str]:
8
+ item = getattr(_pytest_context, "current_item", None)
9
+ return item.nodeid if item is not None else None
@@ -15,11 +15,13 @@ class NetworkConfig(str, Enum):
15
15
  @dataclass
16
16
  class PluginConfig:
17
17
  contracts_dir: Optional[Path] = None
18
+ artifacts_dir: Optional[Path] = None
18
19
  rpc_url: Optional[str] = None
19
20
  default_wait_interval: Optional[int] = None
20
21
  default_wait_retries: Optional[int] = None
21
22
  network_name: Optional[str] = None
22
23
  test_with_mocks: bool = False
24
+ leader_only: bool = False
23
25
 
24
26
 
25
27
  @dataclass
@@ -28,6 +30,7 @@ class NetworkConfigData:
28
30
  url: Optional[str] = None
29
31
  accounts: Optional[List[str]] = None
30
32
  from_account: Optional[str] = None
33
+ leader_only: bool = False
31
34
 
32
35
  def __post_init__(self):
33
36
  if self.id is not None and not isinstance(self.id, int):
@@ -46,10 +49,13 @@ class NetworkConfigData:
46
49
  @dataclass
47
50
  class PathConfig:
48
51
  contracts: Optional[Path] = None
52
+ artifacts: Optional[Path] = None
49
53
 
50
54
  def __post_init__(self):
51
55
  if self.contracts is not None and not isinstance(self.contracts, (str, Path)):
52
56
  raise ValueError("contracts must be a string or Path")
57
+ if self.artifacts is not None and not isinstance(self.artifacts, (str, Path)):
58
+ raise ValueError("artifacts must be a string or Path")
53
59
 
54
60
 
55
61
  @dataclass
@@ -93,6 +99,18 @@ class GeneralConfig:
93
99
  def set_contracts_dir(self, contracts_dir: Path):
94
100
  self.plugin_config.contracts_dir = contracts_dir
95
101
 
102
+ def get_artifacts_dir(self) -> Path:
103
+ if self.plugin_config.artifacts_dir is not None:
104
+ return self.plugin_config.artifacts_dir
105
+ return self.user_config.paths.artifacts
106
+
107
+ def set_artifacts_dir(self, artifacts_dir: Path):
108
+ self.plugin_config.artifacts_dir = artifacts_dir
109
+
110
+ def get_analysis_dir(self) -> Path:
111
+ artifacts_dir = self.get_artifacts_dir()
112
+ return artifacts_dir / "analysis"
113
+
96
114
  def get_rpc_url(self) -> str:
97
115
  if self.plugin_config.rpc_url is not None:
98
116
  return self.plugin_config.rpc_url
@@ -141,8 +159,31 @@ class GeneralConfig:
141
159
  def get_test_with_mocks(self) -> bool:
142
160
  return self.plugin_config.test_with_mocks
143
161
 
162
+ def get_leader_only(self) -> bool:
163
+ if self.plugin_config.leader_only:
164
+ return True
165
+ network_name = self.get_network_name()
166
+ if network_name in self.user_config.networks:
167
+ network_config = self.user_config.networks[network_name]
168
+ return network_config.leader_only
169
+ return False
170
+
144
171
  def check_local_rpc(self) -> bool:
145
172
  SUPPORTED_RPC_DOMAINS = ["localhost", "127.0.0.1"]
146
173
  rpc_url = self.get_rpc_url()
147
174
  domain = urlparse(rpc_url).netloc.split(":")[0] # Extract domain without port
148
175
  return domain in SUPPORTED_RPC_DOMAINS
176
+
177
+ def check_studio_based_rpc(self) -> bool:
178
+ SUPPORTED_RPC_DOMAINS = ["localhost", "127.0.0.1"]
179
+ rpc_url = self.get_rpc_url()
180
+ domain = urlparse(rpc_url).netloc.split(":")[0] # Extract domain without port
181
+
182
+ if domain in SUPPORTED_RPC_DOMAINS:
183
+ return True
184
+
185
+ # Check .genlayer.com or .genlayerlabs.com subdomains
186
+ if domain.endswith(".genlayer.com") or domain.endswith(".genlayerlabs.com"):
187
+ return True
188
+
189
+ return False
gltest_cli/config/user.py CHANGED
@@ -4,20 +4,21 @@ import re
4
4
  from dotenv import load_dotenv
5
5
  from pathlib import Path
6
6
  from functools import lru_cache
7
- from gltest.glchain.account import create_accounts
7
+ from gltest.accounts import create_accounts
8
8
  from gltest_cli.config.constants import (
9
9
  GLTEST_CONFIG_FILE,
10
10
  DEFAULT_NETWORK,
11
11
  DEFAULT_RPC_URL,
12
12
  DEFAULT_ENVIRONMENT,
13
13
  DEFAULT_CONTRACTS_DIR,
14
+ DEFAULT_ARTIFACTS_DIR,
14
15
  DEFAULT_NETWORK_ID,
15
16
  )
16
17
  from gltest_cli.config.types import UserConfig, NetworkConfigData, PathConfig
17
18
 
18
19
  VALID_ROOT_KEYS = ["networks", "paths", "environment"]
19
- VALID_NETWORK_KEYS = ["id", "url", "accounts", "from"]
20
- VALID_PATHS_KEYS = ["contracts"]
20
+ VALID_NETWORK_KEYS = ["id", "url", "accounts", "from", "leader_only"]
21
+ VALID_PATHS_KEYS = ["contracts", "artifacts"]
21
22
 
22
23
 
23
24
  @lru_cache(maxsize=1)
@@ -32,9 +33,12 @@ def get_default_user_config() -> UserConfig:
32
33
  url=DEFAULT_RPC_URL,
33
34
  accounts=accounts_private_keys,
34
35
  from_account=accounts_private_keys[0],
36
+ leader_only=False,
35
37
  ),
36
38
  },
37
- paths=PathConfig(contracts=DEFAULT_CONTRACTS_DIR),
39
+ paths=PathConfig(
40
+ contracts=DEFAULT_CONTRACTS_DIR, artifacts=DEFAULT_ARTIFACTS_DIR
41
+ ),
38
42
  environment=DEFAULT_ENVIRONMENT,
39
43
  default_network=DEFAULT_NETWORK,
40
44
  )
@@ -81,6 +85,10 @@ def validate_network_config(network_name: str, network_config: dict):
81
85
 
82
86
  if "from" in network_config and not isinstance(network_config["from"], str):
83
87
  raise ValueError(f"network {network_name} from must be a string")
88
+ if "leader_only" in network_config and not isinstance(
89
+ network_config["leader_only"], bool
90
+ ):
91
+ raise ValueError(f"network {network_name} leader_only must be a boolean")
84
92
 
85
93
  # For non-default networks, url and accounts are required
86
94
  if network_name != DEFAULT_NETWORK:
@@ -182,18 +190,23 @@ def _get_overridden_networks(raw_config: dict) -> tuple[dict, str]:
182
190
  ]
183
191
  if "from" in network_config:
184
192
  networks_config[network_name].from_account = network_config["from"]
193
+ if "leader_only" in network_config:
194
+ networks_config[network_name].leader_only = network_config[
195
+ "leader_only"
196
+ ]
185
197
  continue
186
198
 
187
199
  url = network_config["url"]
188
200
  accounts = network_config["accounts"]
189
201
  from_account = network_config.get("from", accounts[0])
190
202
  network_id = network_config.get("id")
191
-
203
+ leader_only = network_config.get("leader_only", False)
192
204
  networks_config[network_name] = NetworkConfigData(
193
205
  id=network_id,
194
206
  url=url,
195
207
  accounts=accounts,
196
208
  from_account=from_account,
209
+ leader_only=leader_only,
197
210
  )
198
211
  return networks_config, user_default_network
199
212
 
@@ -208,10 +221,10 @@ def _get_overridden_environment(raw_config: dict) -> str:
208
221
  def _get_overridden_paths(raw_config: dict) -> PathConfig:
209
222
  default_config = get_default_user_config()
210
223
  if "paths" in raw_config:
224
+ paths_config = raw_config.get("paths", {})
211
225
  return PathConfig(
212
- contracts=Path(
213
- raw_config.get("paths", {}).get("contracts", DEFAULT_CONTRACTS_DIR)
214
- )
226
+ contracts=Path(paths_config.get("contracts", DEFAULT_CONTRACTS_DIR)),
227
+ artifacts=Path(paths_config.get("artifacts", DEFAULT_ARTIFACTS_DIR)),
215
228
  )
216
229
  return default_config.paths
217
230
 
@@ -97,4 +97,4 @@ This result should be perfectly parsable by a JSON parser without errors.
97
97
  "winner": self.winner,
98
98
  "score": self.score,
99
99
  "has_resolved": self.has_resolved,
100
- }
100
+ }
@@ -27,11 +27,11 @@ def test_football_prediction_market(setup_validators):
27
27
  contract = factory.deploy(args=["2024-06-26", "Georgia", "Portugal"])
28
28
 
29
29
  # Resolve match
30
- transaction_response_call_1 = contract.resolve(args=[])
30
+ transaction_response_call_1 = contract.resolve(args=[]).transact()
31
31
  assert tx_execution_succeeded(transaction_response_call_1)
32
32
 
33
33
  # Get Updated State
34
- contract_state_2 = contract.get_resolution_data(args=[])
34
+ contract_state_2 = contract.get_resolution_data(args=[]).call()
35
35
 
36
36
  assert contract_state_2["winner"] == 1
37
37
  assert contract_state_2["score"] == "2:0"
@@ -12,7 +12,7 @@ def wait_for_contract_deployment(intelligent_oracle_contract, max_retries=10, de
12
12
  """
13
13
  for _ in range(max_retries):
14
14
  try:
15
- intelligent_oracle_contract.get_dict(args=[])
15
+ intelligent_oracle_contract.get_dict(args=[]).call()
16
16
  return True # If successful, contract is deployed
17
17
  except Exception:
18
18
  time.sleep(delay)
@@ -124,11 +124,11 @@ def test_intelligent_oracle_factory_pattern(setup_validators):
124
124
  market_data["resolution_urls"],
125
125
  market_data["earliest_resolution_date"],
126
126
  ],
127
- )
127
+ ).transact()
128
128
  assert tx_execution_succeeded(create_result)
129
129
 
130
130
  # Get the latest contract address from factory
131
- registered_addresses = registry_contract.get_contract_addresses(args=[])
131
+ registered_addresses = registry_contract.get_contract_addresses(args=[]).call()
132
132
  new_market_address = registered_addresses[-1]
133
133
 
134
134
  # Build a contract object
@@ -145,7 +145,7 @@ def test_intelligent_oracle_factory_pattern(setup_validators):
145
145
 
146
146
  # Verify each market's state
147
147
  for i, market_contract in enumerate(created_market_contracts):
148
- market_state = market_contract.get_dict(args=[])
148
+ market_state = market_contract.get_dict(args=[]).call()
149
149
  expected_data = markets_data[i]
150
150
 
151
151
  # Verify key market properties
@@ -171,10 +171,10 @@ def test_intelligent_oracle_factory_pattern(setup_validators):
171
171
  for i, market_contract in enumerate(created_market_contracts):
172
172
  resolve_result = market_contract.resolve(
173
173
  args=[markets_data[i]["evidence_urls"]],
174
- )
174
+ ).transact()
175
175
  assert tx_execution_succeeded(resolve_result)
176
176
 
177
177
  # Verify market was resolved and has the correct outcome
178
- market_state = market_contract.get_dict(args=[])
178
+ market_state = market_contract.get_dict(args=[]).call()
179
179
  assert market_state["status"] == "Resolved"
180
180
  assert market_state["outcome"] == markets_data[i]["outcome"]
@@ -34,17 +34,17 @@ def test_llm_erc20(setup_validators):
34
34
  contract = factory.deploy(args=[TOKEN_TOTAL_SUPPLY])
35
35
 
36
36
  # Get Initial State
37
- contract_state_1 = contract.get_balances(args=[])
37
+ contract_state_1 = contract.get_balances(args=[]).call()
38
38
  assert contract_state_1[from_account_a.address] == TOKEN_TOTAL_SUPPLY
39
39
 
40
40
  # Transfer from User A to User B
41
41
  transaction_response_call_1 = contract.transfer(
42
42
  args=[TRANSFER_AMOUNT, from_account_b.address]
43
- )
43
+ ).transact()
44
44
  assert tx_execution_succeeded(transaction_response_call_1)
45
45
 
46
46
  # Get Updated State
47
- contract_state_2_1 = contract.get_balances(args=[])
47
+ contract_state_2_1 = contract.get_balances(args=[]).call()
48
48
  assert (
49
49
  contract_state_2_1[from_account_a.address]
50
50
  == TOKEN_TOTAL_SUPPLY - TRANSFER_AMOUNT
@@ -52,9 +52,9 @@ def test_llm_erc20(setup_validators):
52
52
  assert contract_state_2_1[from_account_b.address] == TRANSFER_AMOUNT
53
53
 
54
54
  # Get Updated State
55
- contract_state_2_2 = contract.get_balance_of(args=[from_account_a.address])
55
+ contract_state_2_2 = contract.get_balance_of(args=[from_account_a.address]).call()
56
56
  assert contract_state_2_2 == TOKEN_TOTAL_SUPPLY - TRANSFER_AMOUNT
57
57
 
58
58
  # Get Updated State
59
- contract_state_2_3 = contract.get_balance_of(args=[from_account_b.address])
59
+ contract_state_2_3 = contract.get_balance_of(args=[from_account_b.address]).call()
60
60
  assert contract_state_2_3 == TRANSFER_AMOUNT
@@ -0,0 +1,50 @@
1
+ from gltest import get_contract_factory, get_default_account, create_account
2
+
3
+
4
+ TOKEN_TOTAL_SUPPLY = 1000
5
+ TRANSFER_AMOUNT = 100
6
+
7
+
8
+ def test_llm_erc20_analyze(setup_validators):
9
+ setup_validators()
10
+ # Account Setup
11
+ from_account_a = get_default_account()
12
+ from_account_b = create_account()
13
+
14
+ # Deploy Contract
15
+ factory = get_contract_factory("LlmErc20")
16
+ contract = factory.deploy(args=[TOKEN_TOTAL_SUPPLY])
17
+
18
+ # Get Initial State
19
+ contract_state_1 = contract.get_balances(args=[]).call()
20
+ assert contract_state_1[from_account_a.address] == TOKEN_TOTAL_SUPPLY
21
+
22
+ # Transfer from User A to User B
23
+ stats = contract.transfer(args=[TRANSFER_AMOUNT, from_account_b.address]).analyze(
24
+ provider="openai", model="gpt-4o", runs=3
25
+ )
26
+
27
+ # Verify it's a MethodStatsSummary object
28
+ assert hasattr(stats, "method")
29
+ assert hasattr(stats, "args")
30
+ assert hasattr(stats, "total_runs")
31
+ assert hasattr(stats, "execution_time")
32
+ assert hasattr(stats, "provider")
33
+ assert hasattr(stats, "model")
34
+
35
+ # Check basic properties
36
+ assert stats.method == "transfer"
37
+ assert stats.args == [TRANSFER_AMOUNT, from_account_b.address]
38
+ assert stats.total_runs == 3
39
+ assert stats.provider == "openai"
40
+ assert stats.model == "gpt-4o"
41
+ assert isinstance(stats.execution_time, float)
42
+
43
+ # Check string representation
44
+ stats_str = str(stats)
45
+ assert "Method analysis summary" in stats_str
46
+ assert "Method: transfer" in stats_str
47
+ assert f"Args: [{TRANSFER_AMOUNT}, '{from_account_b.address}']" in stats_str
48
+ assert f"Total runs: {stats.total_runs}" in stats_str
49
+ assert f"Provider: {stats.provider}" in stats_str
50
+ assert f"Model: {stats.model}" in stats_str
@@ -9,56 +9,68 @@ def test_log_indexer(setup_validators):
9
9
  contract = factory.deploy(args=[])
10
10
 
11
11
  # Get closest vector when empty
12
- closest_vector_log_0 = contract.get_closest_vector(args=["I like mango"])
12
+ closest_vector_log_0 = contract.get_closest_vector(args=["I like mango"]).call()
13
13
  assert closest_vector_log_0 is None
14
14
 
15
15
  # Add log 0
16
- transaction_response_add_log_0 = contract.add_log(args=["I like to eat mango", 0])
16
+ transaction_response_add_log_0 = contract.add_log(
17
+ args=["I like to eat mango", 0]
18
+ ).transact()
17
19
  assert tx_execution_succeeded(transaction_response_add_log_0)
18
20
 
19
21
  # Get closest vector to log 0
20
- closest_vector_log_0 = contract.get_closest_vector(args=["I like mango"])
22
+ closest_vector_log_0 = contract.get_closest_vector(args=["I like mango"]).call()
21
23
  closest_vector_log_0 = closest_vector_log_0
22
24
  assert float(closest_vector_log_0["similarity"]) > 0.94
23
25
  assert float(closest_vector_log_0["similarity"]) < 0.95
24
26
 
25
27
  # Add log 1
26
- transaction_response_add_log_1 = contract.add_log(args=["I like carrots", 1])
28
+ transaction_response_add_log_1 = contract.add_log(
29
+ args=["I like carrots", 1]
30
+ ).transact()
27
31
  assert tx_execution_succeeded(transaction_response_add_log_1)
28
32
 
29
33
  # Get closest vector to log 1
30
- closest_vector_log_1 = contract.get_closest_vector(args=["I like carrots"])
34
+ closest_vector_log_1 = contract.get_closest_vector(args=["I like carrots"]).call()
31
35
  closest_vector_log_1 = closest_vector_log_1
32
36
  assert float(closest_vector_log_1["similarity"]) == 1
33
37
 
34
38
  # Update log 0
35
39
  transaction_response_update_log_0 = contract.update_log(
36
40
  args=[0, "I like to eat a lot of mangoes"]
37
- )
41
+ ).transact()
38
42
  assert tx_execution_succeeded(transaction_response_update_log_0)
39
43
 
40
44
  # Get closest vector to log 0
41
- closest_vector_log_0_2 = contract.get_closest_vector(args=["I like mango a lot"])
45
+ closest_vector_log_0_2 = contract.get_closest_vector(
46
+ args=["I like mango a lot"]
47
+ ).call()
42
48
  closest_vector_log_0_2 = closest_vector_log_0_2
43
49
  assert float(closest_vector_log_0_2["similarity"]) > 0.94
44
50
  assert float(closest_vector_log_0_2["similarity"]) < 0.95
45
51
 
46
52
  # Remove log 0
47
- transaction_response_remove_log_0 = contract.remove_log(args=[0])
53
+ transaction_response_remove_log_0 = contract.remove_log(args=[0]).transact()
48
54
  assert tx_execution_succeeded(transaction_response_remove_log_0)
49
55
 
50
56
  # Get closest vector to log 0
51
- closest_vector_log_0_3 = contract.get_closest_vector(args=["I like to eat mango"])
57
+ closest_vector_log_0_3 = contract.get_closest_vector(
58
+ args=["I like to eat mango"]
59
+ ).call()
52
60
  closest_vector_log_0_3 = closest_vector_log_0_3
53
61
  assert float(closest_vector_log_0_3["similarity"]) > 0.67
54
62
  assert float(closest_vector_log_0_3["similarity"]) < 0.68
55
63
 
56
64
  # Add third log
57
- transaction_response_add_log_2 = contract.add_log(args=["This is the third log", 3])
65
+ transaction_response_add_log_2 = contract.add_log(
66
+ args=["This is the third log", 3]
67
+ ).transact()
58
68
  assert tx_execution_succeeded(transaction_response_add_log_2)
59
69
 
60
70
  # Check if new item got id 2
61
- closest_vector_log_2 = contract.get_closest_vector(args=["This is the third log"])
71
+ closest_vector_log_2 = contract.get_closest_vector(
72
+ args=["This is the third log"]
73
+ ).call()
62
74
  assert float(closest_vector_log_2["similarity"]) > 0.99
63
75
  assert closest_vector_log_2["id"] == 3
64
76
  assert closest_vector_log_2["text"] == "This is the third log"
@@ -9,8 +9,8 @@ def test_multi_file_contract(setup_validators):
9
9
  factory = get_contract_factory("MultiFileContract")
10
10
  contract = factory.deploy(args=[])
11
11
 
12
- wait_response = contract.wait(args=[])
12
+ wait_response = contract.wait(args=[]).transact()
13
13
  assert tx_execution_succeeded(wait_response)
14
14
 
15
- res = contract.test(args=[])
15
+ res = contract.test(args=[]).call()
16
16
  assert res == "123"
@@ -9,8 +9,8 @@ def test_multi_file_contract_legacy(setup_validators):
9
9
  factory = get_contract_factory("MultiFileContractLegacy")
10
10
  contract = factory.deploy(args=[])
11
11
 
12
- wait_response = contract.wait(args=[])
12
+ wait_response = contract.wait(args=[]).transact()
13
13
  assert tx_execution_succeeded(wait_response)
14
14
 
15
- res = contract.test(args=[])
15
+ res = contract.test(args=[]).call()
16
16
  assert res == "123"
@@ -61,11 +61,11 @@ def test_multi_read_erc20(setup_validators):
61
61
  from_account_doge.address,
62
62
  [doge_contract.address, shiba_contract.address],
63
63
  ]
64
- )
64
+ ).transact()
65
65
  assert tx_execution_succeeded(transaction_response_call)
66
66
 
67
67
  # check balances
68
- call_method_response_get_balances = multi_read_contract.get_balances(args=[])
68
+ call_method_response_get_balances = multi_read_contract.get_balances(args=[]).call()
69
69
  assert call_method_response_get_balances == {
70
70
  from_account_doge.address: {
71
71
  doge_contract.address: TOKEN_TOTAL_SUPPLY,
@@ -74,20 +74,22 @@ def test_multi_read_erc20(setup_validators):
74
74
  }
75
75
 
76
76
  # update balances for shiba account
77
- transaction_response_call = multi_read_contract.connect(
78
- from_account_shiba
79
- ).update_token_balances(
80
- args=[
81
- from_account_shiba.address,
82
- [doge_contract.address, shiba_contract.address],
83
- ]
77
+ transaction_response_call = (
78
+ multi_read_contract.connect(from_account_shiba)
79
+ .update_token_balances(
80
+ args=[
81
+ from_account_shiba.address,
82
+ [doge_contract.address, shiba_contract.address],
83
+ ]
84
+ )
85
+ .transact()
84
86
  )
85
87
  assert tx_execution_succeeded(transaction_response_call)
86
88
 
87
89
  # check balances
88
- call_method_response_get_balances = multi_read_contract.connect(
89
- from_account_shiba
90
- ).get_balances(args=[])
90
+ call_method_response_get_balances = (
91
+ multi_read_contract.connect(from_account_shiba).get_balances(args=[]).call()
92
+ )
91
93
 
92
94
  assert call_method_response_get_balances == {
93
95
  from_account_doge.address: {