genlayer-test 0.5.1__tar.gz → 0.7.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 (85) hide show
  1. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/PKG-INFO +21 -2
  2. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/README.md +20 -1
  3. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/genlayer_test.egg-info/PKG-INFO +21 -2
  4. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/genlayer_test.egg-info/SOURCES.txt +5 -0
  5. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/contracts/contract.py +24 -0
  6. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/contracts/contract_factory.py +53 -28
  7. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/contracts/contract_functions.py +10 -2
  8. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/contracts/stats_collector.py +11 -4
  9. genlayer_test-0.7.0/gltest/types.py +26 -0
  10. genlayer_test-0.7.0/gltest/utils.py +14 -0
  11. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/pyproject.toml +1 -1
  12. genlayer_test-0.7.0/tests/examples/contracts/invalid_deploy.py +10 -0
  13. genlayer_test-0.7.0/tests/examples/contracts/simple_time_contract.py +85 -0
  14. genlayer_test-0.7.0/tests/examples/tests/test_invalid_deploy.py +24 -0
  15. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_llm_erc20_analyze.py +5 -1
  16. genlayer_test-0.7.0/tests/examples/tests/test_simple_time_contract.py +90 -0
  17. genlayer_test-0.5.1/gltest/types.py +0 -8
  18. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/LICENSE +0 -0
  19. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/genlayer_test.egg-info/dependency_links.txt +0 -0
  20. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/genlayer_test.egg-info/entry_points.txt +0 -0
  21. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/genlayer_test.egg-info/requires.txt +0 -0
  22. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/genlayer_test.egg-info/top_level.txt +0 -0
  23. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/__init__.py +0 -0
  24. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/accounts.py +0 -0
  25. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/artifacts/__init__.py +0 -0
  26. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/artifacts/contract.py +0 -0
  27. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/assertions.py +0 -0
  28. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/clients.py +0 -0
  29. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/contracts/__init__.py +0 -0
  30. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/contracts/method_stats.py +0 -0
  31. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/contracts/utils.py +0 -0
  32. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/exceptions.py +0 -0
  33. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/fixtures.py +0 -0
  34. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/helpers/__init__.py +0 -0
  35. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/helpers/fixture_snapshot.py +0 -0
  36. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/helpers/take_snapshot.py +0 -0
  37. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest/logging.py +0 -0
  38. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest_cli/config/__init__.py +0 -0
  39. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest_cli/config/constants.py +0 -0
  40. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest_cli/config/general.py +0 -0
  41. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest_cli/config/plugin.py +0 -0
  42. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest_cli/config/pytest_context.py +0 -0
  43. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest_cli/config/types.py +0 -0
  44. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest_cli/config/user.py +0 -0
  45. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest_cli/logging.py +0 -0
  46. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/gltest_cli/main.py +0 -0
  47. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/setup.cfg +0 -0
  48. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/__init__.py +0 -0
  49. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/conftest.py +0 -0
  50. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/football_prediction_market.py +0 -0
  51. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/intelligent_oracle.py +0 -0
  52. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/intelligent_oracle_factory.py +0 -0
  53. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/llm_erc20.py +0 -0
  54. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/log_indexer.py +0 -0
  55. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/multi_file_contract/__init__.py +0 -0
  56. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/multi_file_contract/other.py +0 -0
  57. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/multi_read_erc20.py +0 -0
  58. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/multi_tenant_storage.py +0 -0
  59. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/read_erc20.py +0 -0
  60. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/storage.py +0 -0
  61. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/user_storage.py +0 -0
  62. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/contracts/wizard_of_coin.py +0 -0
  63. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_football_prediction_market.py +0 -0
  64. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_intelligent_oracle_factory.py +0 -0
  65. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_llm_erc20.py +0 -0
  66. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_log_indexer.py +0 -0
  67. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_multi_file_contract.py +0 -0
  68. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_multi_read_erc20.py +0 -0
  69. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_multi_tenant_storage.py +0 -0
  70. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_read_erc20.py +0 -0
  71. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_storage.py +0 -0
  72. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_user_storage.py +0 -0
  73. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/examples/tests/test_wizard_of_coin.py +0 -0
  74. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest/__init__.py +0 -0
  75. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest/artifact/__init__.py +0 -0
  76. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest/artifact/contracts/duplicate_ic_contract_1.py +0 -0
  77. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest/artifact/contracts/duplicate_ic_contract_2.py +0 -0
  78. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest/artifact/contracts/not_ic_contract.py +0 -0
  79. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest/artifact/test_contract_definition.py +0 -0
  80. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest/assertions/test_assertions.py +0 -0
  81. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest_cli/__init__.py +0 -0
  82. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest_cli/config/test_config_integration.py +0 -0
  83. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest_cli/config/test_general_config.py +0 -0
  84. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest_cli/config/test_plugin.py +0 -0
  85. {genlayer_test-0.5.1 → genlayer_test-0.7.0}/tests/gltest_cli/config/test_user.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genlayer-test
3
- Version: 0.5.1
3
+ Version: 0.7.0
4
4
  Summary: GenLayer Testing Suite
5
5
  Author: GenLayer
6
6
  License-Expression: MIT
@@ -365,17 +365,24 @@ Key features demonstrated in this contract:
365
365
 
366
366
  ### Contract Deployment
367
367
 
368
+ The GenLayer Testing Suite provides two methods for deploying contracts:
369
+
370
+ 1. **`deploy()`** - Returns the deployed contract instance (recommended for most use cases)
371
+ 2. **`deploy_contract_tx()`** - Returns only the transaction receipt
372
+
368
373
  Here's how to deploy the Storage contract:
369
374
 
370
375
  ```python
371
376
  from gltest import get_contract_factory, get_default_account
377
+ from gltest.assertions import tx_execution_succeeded
378
+ from gltest.utils import extract_contract_address
372
379
 
373
380
  def test_deployment():
374
381
  # Get the contract factory for your contract
375
382
  # it will search in the contracts directory
376
383
  factory = get_contract_factory("Storage")
377
384
 
378
- # Deploy the contract with constructor arguments
385
+ # Method 1: Deploy the contract with constructor arguments (recommended)
379
386
  contract = factory.deploy(
380
387
  args=["initial_value"], # Constructor arguments
381
388
  account=get_default_account(), # Account to deploy from
@@ -384,6 +391,18 @@ def test_deployment():
384
391
 
385
392
  # Contract is now deployed and ready to use
386
393
  assert contract.address is not None
394
+
395
+ # Method 2: Deploy and get only the receipt
396
+ receipt = factory.deploy_contract_tx(
397
+ args=["initial_value"],
398
+ account=get_default_account(),
399
+ )
400
+
401
+ # Verify deployment succeeded
402
+ assert tx_execution_succeeded(receipt)
403
+
404
+ # Get the contract address
405
+ contract_address = extract_contract_address(receipt)
387
406
  ```
388
407
 
389
408
  ### Read Methods
@@ -342,17 +342,24 @@ Key features demonstrated in this contract:
342
342
 
343
343
  ### Contract Deployment
344
344
 
345
+ The GenLayer Testing Suite provides two methods for deploying contracts:
346
+
347
+ 1. **`deploy()`** - Returns the deployed contract instance (recommended for most use cases)
348
+ 2. **`deploy_contract_tx()`** - Returns only the transaction receipt
349
+
345
350
  Here's how to deploy the Storage contract:
346
351
 
347
352
  ```python
348
353
  from gltest import get_contract_factory, get_default_account
354
+ from gltest.assertions import tx_execution_succeeded
355
+ from gltest.utils import extract_contract_address
349
356
 
350
357
  def test_deployment():
351
358
  # Get the contract factory for your contract
352
359
  # it will search in the contracts directory
353
360
  factory = get_contract_factory("Storage")
354
361
 
355
- # Deploy the contract with constructor arguments
362
+ # Method 1: Deploy the contract with constructor arguments (recommended)
356
363
  contract = factory.deploy(
357
364
  args=["initial_value"], # Constructor arguments
358
365
  account=get_default_account(), # Account to deploy from
@@ -361,6 +368,18 @@ def test_deployment():
361
368
 
362
369
  # Contract is now deployed and ready to use
363
370
  assert contract.address is not None
371
+
372
+ # Method 2: Deploy and get only the receipt
373
+ receipt = factory.deploy_contract_tx(
374
+ args=["initial_value"],
375
+ account=get_default_account(),
376
+ )
377
+
378
+ # Verify deployment succeeded
379
+ assert tx_execution_succeeded(receipt)
380
+
381
+ # Get the contract address
382
+ contract_address = extract_contract_address(receipt)
364
383
  ```
365
384
 
366
385
  ### Read Methods
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genlayer-test
3
- Version: 0.5.1
3
+ Version: 0.7.0
4
4
  Summary: GenLayer Testing Suite
5
5
  Author: GenLayer
6
6
  License-Expression: MIT
@@ -365,17 +365,24 @@ Key features demonstrated in this contract:
365
365
 
366
366
  ### Contract Deployment
367
367
 
368
+ The GenLayer Testing Suite provides two methods for deploying contracts:
369
+
370
+ 1. **`deploy()`** - Returns the deployed contract instance (recommended for most use cases)
371
+ 2. **`deploy_contract_tx()`** - Returns only the transaction receipt
372
+
368
373
  Here's how to deploy the Storage contract:
369
374
 
370
375
  ```python
371
376
  from gltest import get_contract_factory, get_default_account
377
+ from gltest.assertions import tx_execution_succeeded
378
+ from gltest.utils import extract_contract_address
372
379
 
373
380
  def test_deployment():
374
381
  # Get the contract factory for your contract
375
382
  # it will search in the contracts directory
376
383
  factory = get_contract_factory("Storage")
377
384
 
378
- # Deploy the contract with constructor arguments
385
+ # Method 1: Deploy the contract with constructor arguments (recommended)
379
386
  contract = factory.deploy(
380
387
  args=["initial_value"], # Constructor arguments
381
388
  account=get_default_account(), # Account to deploy from
@@ -384,6 +391,18 @@ def test_deployment():
384
391
 
385
392
  # Contract is now deployed and ready to use
386
393
  assert contract.address is not None
394
+
395
+ # Method 2: Deploy and get only the receipt
396
+ receipt = factory.deploy_contract_tx(
397
+ args=["initial_value"],
398
+ account=get_default_account(),
399
+ )
400
+
401
+ # Verify deployment succeeded
402
+ assert tx_execution_succeeded(receipt)
403
+
404
+ # Get the contract address
405
+ contract_address = extract_contract_address(receipt)
387
406
  ```
388
407
 
389
408
  ### Read Methods
@@ -15,6 +15,7 @@ gltest/exceptions.py
15
15
  gltest/fixtures.py
16
16
  gltest/logging.py
17
17
  gltest/types.py
18
+ gltest/utils.py
18
19
  gltest/artifacts/__init__.py
19
20
  gltest/artifacts/contract.py
20
21
  gltest/contracts/__init__.py
@@ -41,11 +42,13 @@ tests/conftest.py
41
42
  tests/examples/contracts/football_prediction_market.py
42
43
  tests/examples/contracts/intelligent_oracle.py
43
44
  tests/examples/contracts/intelligent_oracle_factory.py
45
+ tests/examples/contracts/invalid_deploy.py
44
46
  tests/examples/contracts/llm_erc20.py
45
47
  tests/examples/contracts/log_indexer.py
46
48
  tests/examples/contracts/multi_read_erc20.py
47
49
  tests/examples/contracts/multi_tenant_storage.py
48
50
  tests/examples/contracts/read_erc20.py
51
+ tests/examples/contracts/simple_time_contract.py
49
52
  tests/examples/contracts/storage.py
50
53
  tests/examples/contracts/user_storage.py
51
54
  tests/examples/contracts/wizard_of_coin.py
@@ -53,6 +56,7 @@ tests/examples/contracts/multi_file_contract/__init__.py
53
56
  tests/examples/contracts/multi_file_contract/other.py
54
57
  tests/examples/tests/test_football_prediction_market.py
55
58
  tests/examples/tests/test_intelligent_oracle_factory.py
59
+ tests/examples/tests/test_invalid_deploy.py
56
60
  tests/examples/tests/test_llm_erc20.py
57
61
  tests/examples/tests/test_llm_erc20_analyze.py
58
62
  tests/examples/tests/test_log_indexer.py
@@ -60,6 +64,7 @@ tests/examples/tests/test_multi_file_contract.py
60
64
  tests/examples/tests/test_multi_read_erc20.py
61
65
  tests/examples/tests/test_multi_tenant_storage.py
62
66
  tests/examples/tests/test_read_erc20.py
67
+ tests/examples/tests/test_simple_time_contract.py
63
68
  tests/examples/tests/test_storage.py
64
69
  tests/examples/tests/test_user_storage.py
65
70
  tests/examples/tests/test_wizard_of_coin.py
@@ -7,7 +7,9 @@ from gltest.types import (
7
7
  GenLayerTransaction,
8
8
  TransactionStatus,
9
9
  TransactionHashVariant,
10
+ TransactionContext,
10
11
  )
12
+ from genlayer_py.types import SimConfig
11
13
  from typing import List, Any, Optional, Dict, Callable
12
14
  from gltest_cli.config.general import get_general_config
13
15
  from .contract_functions import ContractFunction
@@ -25,14 +27,24 @@ def read_contract_wrapper(
25
27
 
26
28
  def call_method(
27
29
  transaction_hash_variant: TransactionHashVariant = TransactionHashVariant.LATEST_NONFINAL,
30
+ transaction_context: Optional[TransactionContext] = None,
28
31
  ):
29
32
  client = get_gl_client()
33
+ sim_config = None
34
+ if transaction_context:
35
+ try:
36
+ sim_config = SimConfig(**transaction_context)
37
+ except TypeError as e:
38
+ raise ValueError(
39
+ f"Invalid transaction_context keys: {sorted(transaction_context.keys())}"
40
+ ) from e
30
41
  return client.read_contract(
31
42
  address=self.address,
32
43
  function_name=method_name,
33
44
  account=self.account,
34
45
  args=args,
35
46
  transaction_hash_variant=transaction_hash_variant,
47
+ sim_config=sim_config,
36
48
  )
37
49
 
38
50
  return ContractFunction(
@@ -59,6 +71,7 @@ def write_contract_wrapper(
59
71
  wait_retries: Optional[int] = None,
60
72
  wait_triggered_transactions: bool = False,
61
73
  wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
74
+ transaction_context: Optional[TransactionContext] = None,
62
75
  ):
63
76
  """
64
77
  Transact the contract method.
@@ -80,6 +93,14 @@ def write_contract_wrapper(
80
93
  else False
81
94
  )
82
95
  client = get_gl_client()
96
+ sim_config = None
97
+ if transaction_context:
98
+ try:
99
+ sim_config = SimConfig(**transaction_context)
100
+ except TypeError as e:
101
+ raise ValueError(
102
+ f"Invalid transaction_context keys: {sorted(transaction_context.keys())}"
103
+ ) from e
83
104
  tx_hash = client.write_contract(
84
105
  address=self.address,
85
106
  function_name=method_name,
@@ -88,6 +109,7 @@ def write_contract_wrapper(
88
109
  consensus_max_rotations=consensus_max_rotations,
89
110
  leader_only=leader_only,
90
111
  args=args,
112
+ sim_config=sim_config,
91
113
  )
92
114
  receipt = client.wait_for_transaction_receipt(
93
115
  transaction_hash=tx_hash,
@@ -113,6 +135,7 @@ def write_contract_wrapper(
113
135
  plugin: Optional[str] = None,
114
136
  plugin_config: Optional[Dict[str, Any]] = None,
115
137
  runs: int = 100,
138
+ genvm_datetime: Optional[str] = None,
116
139
  ):
117
140
  """
118
141
  Analyze the contract method using StatsCollector.
@@ -129,6 +152,7 @@ def write_contract_wrapper(
129
152
  config=config,
130
153
  plugin=plugin,
131
154
  plugin_config=plugin_config,
155
+ genvm_datetime=genvm_datetime,
132
156
  )
133
157
  sim_results = collector.run_simulations(sim_config, runs)
134
158
  return collector.analyze_results(sim_results, runs, sim_config)
@@ -15,12 +15,15 @@ from gltest.clients import (
15
15
  get_gl_hosted_studio_client,
16
16
  get_local_client,
17
17
  )
18
+ from genlayer_py.types import SimConfig
18
19
  from .contract import Contract
19
20
  from gltest.logging import logger
20
- from gltest.types import TransactionStatus
21
+ from gltest.types import TransactionStatus, GenLayerTransaction, CalldataEncodable
21
22
  from gltest.assertions import tx_execution_failed
22
23
  from gltest.exceptions import DeploymentError
23
24
  from gltest_cli.config.general import get_general_config
25
+ from gltest.utils import extract_contract_address
26
+ from gltest.types import TransactionContext
24
27
 
25
28
 
26
29
  @dataclass
@@ -104,7 +107,7 @@ class ContractFactory:
104
107
 
105
108
  def deploy(
106
109
  self,
107
- args: List[Any] = [],
110
+ args: Optional[List[CalldataEncodable]] = None,
108
111
  account: Optional[LocalAccount] = None,
109
112
  consensus_max_rotations: Optional[int] = None,
110
113
  wait_interval: Optional[int] = None,
@@ -112,9 +115,46 @@ class ContractFactory:
112
115
  wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
113
116
  wait_triggered_transactions: bool = False,
114
117
  wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
118
+ transaction_context: Optional[TransactionContext] = None,
115
119
  ) -> Contract:
116
120
  """
117
- Deploy the contract
121
+ Deploy the contract and return a Contract instance (convenience method).
122
+
123
+ This is a convenience method that handles receipt validation
124
+ and contract instantiation automatically.
125
+ """
126
+ receipt = self.deploy_contract_tx(
127
+ args=args,
128
+ account=account,
129
+ consensus_max_rotations=consensus_max_rotations,
130
+ wait_interval=wait_interval,
131
+ wait_retries=wait_retries,
132
+ wait_transaction_status=wait_transaction_status,
133
+ wait_triggered_transactions=wait_triggered_transactions,
134
+ wait_triggered_transactions_status=wait_triggered_transactions_status,
135
+ transaction_context=transaction_context,
136
+ )
137
+
138
+ if tx_execution_failed(receipt):
139
+ raise DeploymentError(f"Deployment transaction failed: {receipt}")
140
+
141
+ contract_address = extract_contract_address(receipt)
142
+ return self.build_contract(contract_address=contract_address, account=account)
143
+
144
+ def deploy_contract_tx(
145
+ self,
146
+ args: Optional[List[CalldataEncodable]] = None,
147
+ account: Optional[LocalAccount] = None,
148
+ consensus_max_rotations: Optional[int] = None,
149
+ wait_interval: Optional[int] = None,
150
+ wait_retries: Optional[int] = None,
151
+ wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
152
+ wait_triggered_transactions: bool = False,
153
+ wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
154
+ transaction_context: Optional[TransactionContext] = None,
155
+ ) -> GenLayerTransaction:
156
+ """
157
+ Deploy the contract and return the transaction receipt.
118
158
  """
119
159
  general_config = get_general_config()
120
160
  actual_wait_interval = (
@@ -135,12 +175,21 @@ class ContractFactory:
135
175
 
136
176
  client = get_gl_client()
137
177
  try:
178
+ sim_config = None
179
+ if transaction_context:
180
+ try:
181
+ sim_config = SimConfig(**transaction_context)
182
+ except TypeError as e:
183
+ raise ValueError(
184
+ f"Invalid transaction_context keys: {sorted(transaction_context.keys())}"
185
+ ) from e
138
186
  tx_hash = client.deploy_contract(
139
187
  code=self.contract_code,
140
188
  args=args,
141
189
  account=account,
142
190
  consensus_max_rotations=consensus_max_rotations,
143
191
  leader_only=leader_only,
192
+ sim_config=sim_config,
144
193
  )
145
194
  tx_receipt = client.wait_for_transaction_receipt(
146
195
  transaction_hash=tx_hash,
@@ -148,11 +197,6 @@ class ContractFactory:
148
197
  interval=actual_wait_interval,
149
198
  retries=actual_wait_retries,
150
199
  )
151
- if tx_execution_failed(tx_receipt):
152
- raise ValueError(
153
- f"Deployment transaction finalized with error: {tx_receipt}"
154
- )
155
-
156
200
  if wait_triggered_transactions:
157
201
  triggered_transactions = tx_receipt.get("triggered_transactions", [])
158
202
  for triggered_transaction in triggered_transactions:
@@ -162,26 +206,7 @@ class ContractFactory:
162
206
  interval=actual_wait_interval,
163
207
  retries=actual_wait_retries,
164
208
  )
165
-
166
- if (
167
- "tx_data_decoded" in tx_receipt
168
- and "contract_address" in tx_receipt["tx_data_decoded"]
169
- ):
170
- contract_address = tx_receipt["tx_data_decoded"]["contract_address"]
171
- elif "data" in tx_receipt and "contract_address" in tx_receipt["data"]:
172
- contract_address = tx_receipt["data"]["contract_address"]
173
- else:
174
- raise ValueError("Transaction receipt missing contract address")
175
-
176
- schema = self._get_schema_with_fallback()
177
- if schema is None:
178
- raise ValueError(
179
- "Failed to get schema from all clients (default, hosted studio, and local)"
180
- )
181
-
182
- return Contract.new(
183
- address=contract_address, schema=schema, account=account
184
- )
209
+ return tx_receipt
185
210
  except Exception as e:
186
211
  raise DeploymentError(
187
212
  f"Failed to deploy contract {self.contract_name}: {str(e)}"
@@ -1,6 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Callable, Optional, Dict, Any
3
- from gltest.types import TransactionStatus, TransactionHashVariant
3
+ from gltest.types import TransactionStatus, TransactionHashVariant, TransactionContext
4
4
 
5
5
 
6
6
  @dataclass
@@ -14,10 +14,14 @@ class ContractFunction:
14
14
  def call(
15
15
  self,
16
16
  transaction_hash_variant: TransactionHashVariant = TransactionHashVariant.LATEST_NONFINAL,
17
+ transaction_context: Optional[TransactionContext] = None,
17
18
  ):
18
19
  if not self.read_only:
19
20
  raise ValueError("call() not implemented for non-readonly method")
20
- return self.call_method(transaction_hash_variant=transaction_hash_variant)
21
+ return self.call_method(
22
+ transaction_hash_variant=transaction_hash_variant,
23
+ transaction_context=transaction_context,
24
+ )
21
25
 
22
26
  def transact(
23
27
  self,
@@ -28,6 +32,7 @@ class ContractFunction:
28
32
  wait_retries: Optional[int] = None,
29
33
  wait_triggered_transactions: bool = False,
30
34
  wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
35
+ transaction_context: Optional[TransactionContext] = None,
31
36
  ):
32
37
  if self.read_only:
33
38
  raise ValueError("Cannot transact read-only method")
@@ -39,6 +44,7 @@ class ContractFunction:
39
44
  wait_retries=wait_retries,
40
45
  wait_triggered_transactions=wait_triggered_transactions,
41
46
  wait_triggered_transactions_status=wait_triggered_transactions_status,
47
+ transaction_context=transaction_context,
42
48
  )
43
49
 
44
50
  def analyze(
@@ -49,6 +55,7 @@ class ContractFunction:
49
55
  plugin: Optional[str] = None,
50
56
  plugin_config: Optional[Dict[str, Any]] = None,
51
57
  runs: int = 100,
58
+ genvm_datetime: Optional[str] = None,
52
59
  ):
53
60
  if self.read_only:
54
61
  raise ValueError("Cannot analyze read-only method")
@@ -59,4 +66,5 @@ class ContractFunction:
59
66
  plugin=plugin,
60
67
  plugin_config=plugin_config,
61
68
  runs=runs,
69
+ genvm_datetime=genvm_datetime,
62
70
  )
@@ -29,6 +29,7 @@ class SimulationConfig:
29
29
  config: Optional[Dict[str, Any]] = None
30
30
  plugin: Optional[str] = None
31
31
  plugin_config: Optional[Dict[str, Any]] = None
32
+ genvm_datetime: Optional[str] = None
32
33
 
33
34
 
34
35
  @dataclass
@@ -103,7 +104,12 @@ class StatsCollector:
103
104
  self, sim_config: SimulationConfig
104
105
  ) -> Dict[str, Any]:
105
106
  """Execute a single simulation."""
106
- config_dict = {
107
+ config_dict = {}
108
+
109
+ if sim_config.genvm_datetime is not None:
110
+ config_dict["genvm_datetime"] = sim_config.genvm_datetime
111
+
112
+ validator_info = {
107
113
  "provider": sim_config.provider,
108
114
  "model": sim_config.model,
109
115
  }
@@ -113,9 +119,10 @@ class StatsCollector:
113
119
  and sim_config.plugin is not None
114
120
  and sim_config.plugin_config is not None
115
121
  ):
116
- config_dict["config"] = sim_config.config
117
- config_dict["plugin"] = sim_config.plugin
118
- config_dict["plugin_config"] = sim_config.plugin_config
122
+ validator_info["config"] = sim_config.config
123
+ validator_info["plugin"] = sim_config.plugin
124
+ validator_info["plugin_config"] = sim_config.plugin_config
125
+ config_dict["validators"] = [validator_info]
119
126
 
120
127
  return self.client.simulate_write_contract(
121
128
  address=self.contract_address,
@@ -0,0 +1,26 @@
1
+ # Re-export genlayer-py types
2
+ from genlayer_py.types import (
3
+ CalldataAddress,
4
+ GenLayerTransaction,
5
+ TransactionStatus,
6
+ CalldataEncodable,
7
+ TransactionHashVariant,
8
+ )
9
+ from typing import List, TypedDict, Dict, Any
10
+
11
+
12
+ class ValidatorConfig(TypedDict):
13
+ """Validator information."""
14
+
15
+ provider: str
16
+ model: str
17
+ config: Dict[str, Any]
18
+ plugin: str
19
+ plugin_config: Dict[str, Any]
20
+
21
+
22
+ class TransactionContext(TypedDict, total=False):
23
+ """Context for consensus operations."""
24
+
25
+ validators: List[ValidatorConfig] # List to create virtual validators
26
+ genvm_datetime: str # ISO format datetime string
@@ -0,0 +1,14 @@
1
+ from genlayer_py.types import GenLayerTransaction
2
+
3
+
4
+ def extract_contract_address(receipt: GenLayerTransaction) -> str:
5
+ """Extract contract address from a deployment transaction receipt."""
6
+ if (
7
+ "tx_data_decoded" in receipt
8
+ and "contract_address" in receipt["tx_data_decoded"]
9
+ ):
10
+ return receipt["tx_data_decoded"]["contract_address"]
11
+ elif "data" in receipt and "contract_address" in receipt["data"]:
12
+ return receipt["data"]["contract_address"]
13
+ else:
14
+ raise ValueError("Transaction receipt missing contract address")
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "genlayer-test"
7
- version = "0.5.1"
7
+ version = "0.7.0"
8
8
  description = "GenLayer Testing Suite"
9
9
  authors = [
10
10
  { name = "GenLayer" }
@@ -0,0 +1,10 @@
1
+ # { "Depends": "py-genlayer:test" }
2
+
3
+ import genlayer as gl
4
+
5
+
6
+ class InvalidDeploy(gl.Contract):
7
+ """Contract that always fails during deployment"""
8
+
9
+ def __init__(self):
10
+ raise Exception("This is an invalid deploy")
@@ -0,0 +1,85 @@
1
+ # {
2
+ # "Seq": [
3
+ # { "Depends": "py-lib-genlayer-embeddings:09h0i209wrzh4xzq86f79c60x0ifs7xcjwl53ysrnw06i54ddxyi" },
4
+ # { "Depends": "py-genlayer:1j12s63yfjpva9ik2xgnffgrs6v44y1f52jvj9w7xvdn7qckd379" }
5
+ # ]
6
+ # }
7
+
8
+ from datetime import datetime, timezone
9
+ from genlayer import *
10
+
11
+
12
+ class SimpleTimeContract(gl.Contract):
13
+ """
14
+ A simple contract that demonstrates time-based function availability.
15
+ """
16
+
17
+ start_date: str # ISO format datetime string
18
+ data: str
19
+ is_active: bool
20
+
21
+ def __init__(self, start_datetime_iso: str):
22
+ """
23
+ Initialize the contract with a required start date (ISO 8601).
24
+ """
25
+ self.start_date = start_datetime_iso
26
+ self.is_active = False
27
+ self.data = ""
28
+
29
+ def _days_since_start(self) -> int:
30
+ """Calculate days elapsed since start date."""
31
+ current = datetime.now(timezone.utc)
32
+ start = datetime.fromisoformat(self.start_date)
33
+ print(f"Current: {current}, Start: {start}")
34
+ delta = current - start
35
+ print(f"Delta: {delta}")
36
+ return delta.days
37
+
38
+ @gl.public.write
39
+ def activate(self):
40
+ """
41
+ Activate the contract.
42
+ Only works if current date is after start date.
43
+ """
44
+ days = self._days_since_start()
45
+
46
+ if days < 0:
47
+ raise ValueError(
48
+ f"Cannot activate before start date. Days until start: {abs(days)}"
49
+ )
50
+
51
+ self.is_active = True
52
+
53
+ @gl.public.write
54
+ def set_data(self, value: str):
55
+ """
56
+ Set data in the contract.
57
+ Only works if contract is active and within 30 days of start.
58
+ """
59
+ if not self.is_active:
60
+ raise ValueError("Contract must be activated first")
61
+
62
+ days = self._days_since_start()
63
+
64
+ if days > 30:
65
+ raise ValueError(
66
+ f"Function expired. Was available for 30 days after start, now at day {days}"
67
+ )
68
+
69
+ self.data = value
70
+
71
+ @gl.public.view
72
+ def get_status(self) -> dict:
73
+ """Get current contract status."""
74
+ days = self._days_since_start()
75
+ current = datetime.now(timezone.utc)
76
+
77
+ return {
78
+ "start_date": self.start_date,
79
+ "current_time": current.isoformat(),
80
+ "days_since_start": days,
81
+ "is_active": self.is_active,
82
+ "data": self.data,
83
+ "can_activate": days >= 0 and not self.is_active,
84
+ "can_set_data": self.is_active and 0 <= days <= 30,
85
+ }
@@ -0,0 +1,24 @@
1
+ import pytest
2
+ from gltest import get_contract_factory
3
+ from gltest.assertions import tx_execution_failed
4
+ from gltest.exceptions import DeploymentError
5
+
6
+
7
+ def test_invalid_deploy_basic_exception(setup_validators):
8
+ """Test deployment failure with basic exception"""
9
+ setup_validators()
10
+ factory = get_contract_factory("InvalidDeploy")
11
+
12
+ # Deployment should fail with exception
13
+ with pytest.raises(DeploymentError):
14
+ factory.deploy()
15
+
16
+
17
+ def test_invalid_deploy_receipt_only(setup_validators):
18
+ """Test deployment failure using deploy_contract_tx() method that returns receipt only"""
19
+ setup_validators()
20
+ factory = get_contract_factory("InvalidDeploy")
21
+
22
+ # Deploy and get receipt - should show failure
23
+ receipt = factory.deploy_contract_tx()
24
+ assert tx_execution_failed(receipt)
@@ -1,4 +1,5 @@
1
1
  from gltest import get_contract_factory, get_default_account, create_account
2
+ from datetime import datetime, timezone
2
3
 
3
4
 
4
5
  TOKEN_TOTAL_SUPPLY = 1000
@@ -21,7 +22,10 @@ def test_llm_erc20_analyze(setup_validators):
21
22
 
22
23
  # Transfer from User A to User B
23
24
  stats = contract.transfer(args=[TRANSFER_AMOUNT, from_account_b.address]).analyze(
24
- provider="openai", model="gpt-4o", runs=3
25
+ provider="openai",
26
+ model="gpt-4o",
27
+ runs=3,
28
+ genvm_datetime=datetime.now(timezone.utc).isoformat(),
25
29
  )
26
30
 
27
31
  # Verify it's a MethodStatsSummary object
@@ -0,0 +1,90 @@
1
+ from gltest import get_contract_factory
2
+ from datetime import datetime, timedelta, timezone
3
+ from gltest.assertions import tx_execution_succeeded, tx_execution_failed
4
+
5
+
6
+ def test_simple_time_contract():
7
+ """Test all time-based functionality in a single comprehensive test."""
8
+
9
+ factory = get_contract_factory("SimpleTimeContract")
10
+
11
+ # Test 1: Deploy with past start date (10 days ago)
12
+ now = datetime.now(timezone.utc)
13
+ past_date = (now - timedelta(days=10)).isoformat()
14
+ contract = factory.deploy(args=[past_date])
15
+
16
+ # Test 1: Check initial status (10 days after start)
17
+ status = contract.get_status().call()
18
+ assert status["is_active"] == False
19
+ assert status["days_since_start"] == 10
20
+ assert status["can_activate"] == True
21
+
22
+ # Test 2: Try to activate before start date (simulate going back in time)
23
+ before_start_date = now - timedelta(days=15) # 5 days before start
24
+ before_start_date_receipt = contract.activate().transact(
25
+ transaction_context={
26
+ "genvm_datetime": before_start_date.isoformat(),
27
+ },
28
+ )
29
+ assert tx_execution_failed(before_start_date_receipt)
30
+
31
+ # Test 3: Activate after start date
32
+ activate_date = now - timedelta(days=5) # 5 days after start (15 days ago + 10)
33
+ activate_receipt = contract.activate().transact(
34
+ transaction_context={
35
+ "genvm_datetime": activate_date.isoformat(),
36
+ },
37
+ )
38
+ assert tx_execution_succeeded(activate_receipt)
39
+
40
+ # Test 4: Verify activation and check status
41
+ status = contract.get_status().call(
42
+ transaction_context={
43
+ "genvm_datetime": activate_date.isoformat(),
44
+ },
45
+ )
46
+ assert status["is_active"] == True
47
+ assert status["days_since_start"] == 5
48
+ assert status["can_set_data"] == True
49
+
50
+ # Test 5: Set data within valid period (within 30 days)
51
+ set_data_date = now - timedelta(days=2) # 8 days after start
52
+ test_data = "Test data within valid period"
53
+ set_data_receipt = contract.set_data(
54
+ args=[test_data],
55
+ ).transact(
56
+ transaction_context={
57
+ "genvm_datetime": set_data_date.isoformat(),
58
+ }
59
+ )
60
+ assert tx_execution_succeeded(set_data_receipt)
61
+
62
+ # Test 6: Verify data was set
63
+ status = contract.get_status().call(
64
+ transaction_context={
65
+ "genvm_datetime": set_data_date.isoformat(),
66
+ },
67
+ )
68
+ assert status["data"] == test_data
69
+ assert status["days_since_start"] == 8
70
+
71
+ # Test 7: Try to set data after 30 days (should fail)
72
+ expired_date = now + timedelta(days=25) # 35 days after start
73
+ expired_date_receipt = contract.set_data(
74
+ args=["Should fail - expired"],
75
+ ).transact(
76
+ transaction_context={
77
+ "genvm_datetime": expired_date.isoformat(),
78
+ }
79
+ )
80
+ assert tx_execution_failed(expired_date_receipt)
81
+
82
+ # Test 8: Check status shows expired
83
+ status = contract.get_status().call(
84
+ transaction_context={
85
+ "genvm_datetime": expired_date.isoformat(),
86
+ },
87
+ )
88
+ assert status["is_active"] == True # Still active
89
+ assert status["can_set_data"] == False # But can't set data
90
+ assert status["days_since_start"] == 35
@@ -1,8 +0,0 @@
1
- # Re-export genlayer-py types
2
- from genlayer_py.types import (
3
- CalldataAddress,
4
- GenLayerTransaction,
5
- TransactionStatus,
6
- CalldataEncodable,
7
- TransactionHashVariant,
8
- )
File without changes
File without changes