wayfinder-paths 0.1.8__py3-none-any.whl → 0.1.9__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 (47) hide show
  1. wayfinder_paths/CONFIG_GUIDE.md +5 -14
  2. wayfinder_paths/adapters/brap_adapter/README.md +1 -1
  3. wayfinder_paths/adapters/brap_adapter/adapter.py +0 -51
  4. wayfinder_paths/adapters/hyperlend_adapter/adapter.py +0 -7
  5. wayfinder_paths/adapters/hyperliquid_adapter/adapter.py +0 -54
  6. wayfinder_paths/adapters/hyperliquid_adapter/test_adapter_live.py +1 -1
  7. wayfinder_paths/adapters/ledger_adapter/README.md +1 -1
  8. wayfinder_paths/adapters/pool_adapter/README.md +1 -77
  9. wayfinder_paths/adapters/pool_adapter/adapter.py +0 -122
  10. wayfinder_paths/adapters/pool_adapter/examples.json +0 -57
  11. wayfinder_paths/adapters/pool_adapter/test_adapter.py +0 -86
  12. wayfinder_paths/adapters/token_adapter/README.md +1 -1
  13. wayfinder_paths/core/clients/AuthClient.py +0 -3
  14. wayfinder_paths/core/clients/ClientManager.py +1 -22
  15. wayfinder_paths/core/clients/WalletClient.py +0 -8
  16. wayfinder_paths/core/clients/WayfinderClient.py +9 -14
  17. wayfinder_paths/core/clients/__init__.py +0 -8
  18. wayfinder_paths/core/clients/protocols.py +0 -60
  19. wayfinder_paths/core/config.py +5 -45
  20. wayfinder_paths/core/engine/StrategyJob.py +0 -3
  21. wayfinder_paths/core/services/base.py +0 -49
  22. wayfinder_paths/core/services/local_evm_txn.py +3 -82
  23. wayfinder_paths/core/services/local_token_txn.py +61 -70
  24. wayfinder_paths/core/services/web3_service.py +0 -2
  25. wayfinder_paths/core/settings.py +8 -8
  26. wayfinder_paths/core/strategies/Strategy.py +1 -5
  27. wayfinder_paths/core/utils/evm_helpers.py +7 -12
  28. wayfinder_paths/core/wallets/README.md +3 -6
  29. wayfinder_paths/run_strategy.py +29 -32
  30. wayfinder_paths/scripts/make_wallets.py +1 -25
  31. wayfinder_paths/scripts/run_strategy.py +0 -2
  32. wayfinder_paths/strategies/basis_trading_strategy/snapshot_mixin.py +1 -3
  33. wayfinder_paths/strategies/basis_trading_strategy/strategy.py +86 -137
  34. wayfinder_paths/strategies/basis_trading_strategy/test_strategy.py +96 -58
  35. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/README.md +2 -2
  36. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/examples.json +4 -1
  37. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/strategy.py +106 -28
  38. wayfinder_paths/strategies/hyperlend_stable_yield_strategy/test_strategy.py +53 -14
  39. wayfinder_paths/strategies/stablecoin_yield_strategy/strategy.py +1 -6
  40. wayfinder_paths/strategies/stablecoin_yield_strategy/test_strategy.py +0 -4
  41. wayfinder_paths/templates/strategy/test_strategy.py +0 -4
  42. {wayfinder_paths-0.1.8.dist-info → wayfinder_paths-0.1.9.dist-info}/METADATA +5 -15
  43. {wayfinder_paths-0.1.8.dist-info → wayfinder_paths-0.1.9.dist-info}/RECORD +45 -47
  44. wayfinder_paths/core/clients/SimulationClient.py +0 -192
  45. wayfinder_paths/core/clients/TransactionClient.py +0 -63
  46. {wayfinder_paths-0.1.8.dist-info → wayfinder_paths-0.1.9.dist-info}/LICENSE +0 -0
  47. {wayfinder_paths-0.1.8.dist-info → wayfinder_paths-0.1.9.dist-info}/WHEEL +0 -0
@@ -1,15 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from decimal import ROUND_DOWN, Decimal
3
4
  from typing import Any
4
5
 
5
6
  from eth_utils import to_checksum_address
6
7
  from loguru import logger
7
- from web3 import AsyncWeb3
8
+ from web3 import AsyncWeb3, Web3
8
9
 
9
10
  from wayfinder_paths.core.clients.TokenClient import TokenClient
10
- from wayfinder_paths.core.clients.TransactionClient import TransactionClient
11
11
  from wayfinder_paths.core.constants import ZERO_ADDRESS
12
- from wayfinder_paths.core.constants.erc20_abi import ERC20_APPROVAL_ABI
12
+ from wayfinder_paths.core.constants.erc20_abi import ERC20_ABI, ERC20_APPROVAL_ABI
13
13
  from wayfinder_paths.core.services.base import EvmTxn, TokenTxn
14
14
  from wayfinder_paths.core.utils.evm_helpers import resolve_chain_id
15
15
 
@@ -22,13 +22,12 @@ class LocalTokenTxnService(TokenTxn):
22
22
  config: dict[str, Any] | None,
23
23
  *,
24
24
  wallet_provider: EvmTxn,
25
- simulation: bool = False,
26
25
  ) -> None:
27
- del config, simulation
26
+ del config
28
27
  self.wallet_provider = wallet_provider
29
28
  self.logger = logger.bind(service="DefaultEvmTransactionService")
30
29
  self.token_client = TokenClient()
31
- self.builder = _EvmTransactionBuilder()
30
+ self.builder = _EvmTransactionBuilder(wallet_provider)
32
31
 
33
32
  async def build_send(
34
33
  self,
@@ -51,14 +50,24 @@ class LocalTokenTxnService(TokenTxn):
51
50
  return False, f"Token {token_id} is missing a chain id"
52
51
 
53
52
  token_address = (token_meta or {}).get("address") or ZERO_ADDRESS
53
+ is_native = not token_address or token_address.lower() == ZERO_ADDRESS.lower()
54
+
55
+ if is_native:
56
+ amount_wei = self._to_base_units(
57
+ amount, 18
58
+ ) # Native tokens use 18 decimals
59
+ else:
60
+ decimals = int((token_meta or {}).get("decimals") or 18)
61
+ amount_wei = self._to_base_units(amount, decimals)
54
62
 
55
63
  try:
56
64
  tx = await self.builder.build_send_transaction(
57
65
  from_address=from_address,
58
66
  to_address=to_address,
59
67
  token_address=token_address,
60
- amount=amount,
68
+ amount=amount_wei,
61
69
  chain_id=int(chain_id),
70
+ is_native=is_native,
62
71
  )
63
72
  except Exception as exc: # noqa: BLE001
64
73
  return False, f"Failed to build send transaction: {exc}"
@@ -127,12 +136,20 @@ class LocalTokenTxnService(TokenTxn):
127
136
  raise ValueError("Chain ID is required")
128
137
  return int(chain_id)
129
138
 
139
+ def _to_base_units(self, amount: float, decimals: int) -> int:
140
+ """Convert human-readable amount to base units (wei for native, token units for ERC20)."""
141
+ scale = Decimal(10) ** int(decimals)
142
+ quantized = (Decimal(str(amount)) * scale).to_integral_value(
143
+ rounding=ROUND_DOWN
144
+ )
145
+ return int(quantized)
146
+
130
147
 
131
148
  class _EvmTransactionBuilder:
132
149
  """Helpers that only build transaction dictionaries for sends and approvals."""
133
150
 
134
- def __init__(self) -> None:
135
- self.transaction_client = TransactionClient()
151
+ def __init__(self, wallet_provider: EvmTxn) -> None:
152
+ self.wallet_provider = wallet_provider
136
153
 
137
154
  async def build_send_transaction(
138
155
  self,
@@ -140,22 +157,37 @@ class _EvmTransactionBuilder:
140
157
  from_address: str,
141
158
  to_address: str,
142
159
  token_address: str | None,
143
- amount: float,
160
+ amount: int,
144
161
  chain_id: int,
162
+ is_native: bool,
145
163
  ) -> dict[str, Any]:
146
164
  """Build the transaction dict for sending native or ERC20 tokens."""
147
- payload = await self.transaction_client.build_send(
148
- from_address=from_address,
149
- to_address=to_address,
150
- token_address=token_address or "",
151
- amount=float(amount),
152
- chain_id=int(chain_id),
153
- )
154
- return self._payload_to_tx(
155
- payload=payload,
156
- from_address=from_address,
157
- is_native=not token_address or token_address.lower() == ZERO_ADDRESS,
158
- )
165
+ from_checksum = to_checksum_address(from_address)
166
+ to_checksum = to_checksum_address(to_address)
167
+ chain_id_int = int(chain_id)
168
+
169
+ if is_native:
170
+ return {
171
+ "chainId": chain_id_int,
172
+ "from": from_checksum,
173
+ "to": to_checksum,
174
+ "value": int(amount),
175
+ }
176
+
177
+ token_checksum = to_checksum_address(token_address or ZERO_ADDRESS)
178
+ w3_sync = Web3()
179
+ contract = w3_sync.eth.contract(address=token_checksum, abi=ERC20_ABI)
180
+ data = contract.functions.transfer(
181
+ to_checksum, int(amount)
182
+ )._encode_transaction_data()
183
+
184
+ return {
185
+ "chainId": chain_id_int,
186
+ "from": from_checksum,
187
+ "to": token_checksum,
188
+ "data": data,
189
+ "value": 0,
190
+ }
159
191
 
160
192
  def build_erc20_approval_transaction(
161
193
  self,
@@ -173,10 +205,13 @@ class _EvmTransactionBuilder:
173
205
  from_checksum = to_checksum_address(from_address)
174
206
  amount_int = int(amount)
175
207
 
176
- contract = web3.eth.contract(address=token_checksum, abi=ERC20_APPROVAL_ABI)
177
- data = contract.encodeABI(
178
- fn_name="approve", args=[spender_checksum, amount_int]
179
- )
208
+ # Use synchronous Web3 for encoding (encodeABI doesn't exist in web3.py v7)
209
+ w3_sync = Web3()
210
+ contract = w3_sync.eth.contract(address=token_checksum, abi=ERC20_APPROVAL_ABI)
211
+ # In web3.py v7, use _encode_transaction_data to encode without network calls
212
+ data = contract.functions.approve(
213
+ spender_checksum, amount_int
214
+ )._encode_transaction_data()
180
215
 
181
216
  return {
182
217
  "chainId": int(chain_id),
@@ -185,47 +220,3 @@ class _EvmTransactionBuilder:
185
220
  "data": data,
186
221
  "value": 0,
187
222
  }
188
-
189
- def _payload_to_tx(
190
- self, payload: dict[str, Any], from_address: str, is_native: bool
191
- ) -> dict[str, Any]:
192
- data_root = payload.get("data", payload)
193
- tx_src = data_root.get("transaction") or data_root
194
-
195
- chain_id = tx_src.get("chainId") or data_root.get("chain_id")
196
- if chain_id is None:
197
- raise ValueError("Transaction payload missing chainId")
198
-
199
- tx: dict[str, Any] = {"chainId": int(chain_id)}
200
- tx["from"] = to_checksum_address(from_address)
201
-
202
- if tx_src.get("to"):
203
- tx["to"] = to_checksum_address(tx_src["to"])
204
- if tx_src.get("data"):
205
- data = tx_src["data"]
206
- tx["data"] = data if str(data).startswith("0x") else f"0x{data}"
207
-
208
- val = tx_src.get("value", 0)
209
- tx["value"] = self._normalize_value(val) if is_native else 0
210
-
211
- if tx_src.get("gas"):
212
- tx["gas"] = int(tx_src["gas"])
213
- if tx_src.get("maxFeePerGas"):
214
- tx["maxFeePerGas"] = int(tx_src["maxFeePerGas"])
215
- if tx_src.get("maxPriorityFeePerGas"):
216
- tx["maxPriorityFeePerGas"] = int(tx_src["maxPriorityFeePerGas"])
217
- if tx_src.get("gasPrice"):
218
- tx["gasPrice"] = int(tx_src["gasPrice"])
219
- if tx_src.get("nonce") is not None:
220
- tx["nonce"] = int(tx_src["nonce"])
221
-
222
- return tx
223
-
224
- def _normalize_value(self, value: Any) -> int:
225
- if isinstance(value, str):
226
- if value.startswith("0x"):
227
- return int(value, 16)
228
- return int(float(value))
229
- if isinstance(value, (int, float)):
230
- return int(value)
231
- return 0
@@ -16,7 +16,6 @@ class DefaultWeb3Service(Web3Service):
16
16
  *,
17
17
  wallet_provider: EvmTxn | None = None,
18
18
  evm_transactions: TokenTxn | None = None,
19
- simulation: bool = False,
20
19
  ) -> None:
21
20
  """
22
21
  Initialize the service with optional dependency injection.
@@ -33,7 +32,6 @@ class DefaultWeb3Service(Web3Service):
33
32
  self._evm_transactions = LocalTokenTxnService(
34
33
  config=cfg,
35
34
  wallet_provider=self._wallet_provider,
36
- simulation=simulation,
37
35
  )
38
36
 
39
37
  @property
@@ -12,14 +12,14 @@ class CoreSettings(BaseSettings):
12
12
  """
13
13
 
14
14
  model_config = SettingsConfigDict(
15
- env_file=".env",
16
- env_file_encoding="utf-8",
15
+ # Note: .env file is only used for publishing (REPOSITORY_NAME, PUBLISH_TOKEN)
16
+ # All other configuration should come from config.json
17
17
  case_sensitive=False,
18
18
  extra="ignore", # Ignore extra environment variables (e.g., from Django)
19
19
  )
20
20
 
21
21
  # Core API Configuration
22
- API_ENV: str = Field("development", env="API_ENV")
22
+ API_ENV: str = Field(default="development")
23
23
 
24
24
  def _compute_default_api_url() -> str:
25
25
  """
@@ -44,17 +44,17 @@ class CoreSettings(BaseSettings):
44
44
  base = "https://wayfinder.ai/api/v1"
45
45
  return base
46
46
 
47
- WAYFINDER_API_URL: str = Field(_compute_default_api_url(), env="WAYFINDER_API_URL")
47
+ WAYFINDER_API_URL: str = Field(default_factory=_compute_default_api_url)
48
48
 
49
49
  # Network Configuration
50
- NETWORK: str = Field("testnet", env="NETWORK") # mainnet, testnet, devnet
50
+ NETWORK: str = Field(default="testnet") # mainnet, testnet, devnet
51
51
 
52
52
  # Logging
53
- LOG_LEVEL: str = Field("INFO", env="LOG_LEVEL")
54
- LOG_FILE: str = Field("logs/strategy.log", env="LOG_FILE")
53
+ LOG_LEVEL: str = Field(default="INFO")
54
+ LOG_FILE: str = Field(default="logs/strategy.log")
55
55
 
56
56
  # Safety
57
- DRY_RUN: bool = Field(False, env="DRY_RUN")
57
+ DRY_RUN: bool = Field(default=False)
58
58
 
59
59
 
60
60
  # Core settings instance
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import os
4
3
  import traceback
5
4
  from abc import ABC, abstractmethod
6
5
  from collections.abc import Awaitable, Callable
@@ -57,16 +56,13 @@ class Strategy(ABC):
57
56
  *,
58
57
  main_wallet: WalletConfig | dict[str, Any] | None = None,
59
58
  strategy_wallet: WalletConfig | dict[str, Any] | None = None,
60
- simulation: bool = False,
61
59
  web3_service: Web3Service | None = None,
62
60
  api_key: str | None = None,
63
61
  ):
64
62
  self.adapters = {}
65
63
  self.ledger_adapter = None
66
64
  self.logger = logger.bind(strategy=self.__class__.__name__)
67
- if api_key:
68
- os.environ["WAYFINDER_API_KEY"] = api_key
69
-
65
+ # Note: api_key is passed to ClientManager, not set in environment
70
66
  self.config = config
71
67
 
72
68
  async def setup(self) -> None:
@@ -59,7 +59,7 @@ def resolve_rpc_url(
59
59
  explicit_rpc_url: str | None = None,
60
60
  ) -> str:
61
61
  """
62
- Resolve RPC URL from config or environment variables.
62
+ Resolve RPC URL from config.
63
63
 
64
64
  Args:
65
65
  chain_id: Chain ID to look up RPC URL for
@@ -83,10 +83,7 @@ def resolve_rpc_url(
83
83
  by_str = mapping.get(str(chain_id))
84
84
  if by_str:
85
85
  return str(by_str)
86
- env_rpc = os.getenv("RPC_URL")
87
- if env_rpc:
88
- return env_rpc
89
- raise ValueError("RPC URL not provided. Set strategy.rpc_urls or env RPC_URL.")
86
+ raise ValueError("RPC URL not provided. Set strategy.rpc_urls in config.json.")
90
87
 
91
88
 
92
89
  async def get_next_nonce(
@@ -119,7 +116,7 @@ def resolve_private_key_for_from_address(
119
116
  from_address: str, config: dict[str, Any]
120
117
  ) -> str | None:
121
118
  """
122
- Resolve private key for the given address from config or environment.
119
+ Resolve private key for the given address from config.
123
120
 
124
121
  Args:
125
122
  from_address: Address to resolve private key for
@@ -159,14 +156,12 @@ def resolve_private_key_for_from_address(
159
156
  logger.debug("Error resolving addresses from wallet config: %s", e)
160
157
 
161
158
  if main_addr and from_addr_norm == (main_addr or "").lower():
162
- return main_pk or os.getenv("PRIVATE_KEY")
159
+ return main_pk
163
160
  if strategy_addr and from_addr_norm == (strategy_addr or "").lower():
164
- return (
165
- strategy_pk or os.getenv("PRIVATE_KEY_STRATEGY") or os.getenv("PRIVATE_KEY")
166
- )
161
+ return strategy_pk
167
162
 
168
- # Fallback to environment variables
169
- return os.getenv("PRIVATE_KEY_STRATEGY") or os.getenv("PRIVATE_KEY")
163
+ # No fallback - private keys must be in config or wallets.json
164
+ return None
170
165
 
171
166
 
172
167
  async def _get_abi(chain_id: int, address: str) -> str | None:
@@ -1,6 +1,6 @@
1
1
  # Wallet Abstraction Layer
2
2
 
3
- Wayfinder strategies interact with blockchains through a single abstraction: the `EvmTxn` interface defined in `wayfinder_paths/core/services/base.py`. The default implementation (`LocalEvmTxn`) signs transactions with private keys pulled from config/environment variables, while `WalletManager` resolves which provider to use at runtime.
3
+ Wayfinder strategies interact with blockchains through a single abstraction: the `EvmTxn` interface defined in `wayfinder_paths/core/services/base.py`. The default implementation (`LocalEvmTxn`) signs transactions with private keys pulled from config.json or wallets.json, while `WalletManager` resolves which provider to use at runtime.
4
4
 
5
5
  ## Pieces
6
6
 
@@ -46,9 +46,6 @@ class PrivyWallet(EvmTxn):
46
46
  async def read_erc20_allowance(self, chain_id: int, token_address: str, owner_address: str, spender_address: str) -> tuple[bool, Any]:
47
47
  ...
48
48
 
49
- async def approve_token(...):
50
- ...
51
-
52
49
  async def broadcast_transaction(...):
53
50
  ...
54
51
 
@@ -76,8 +73,8 @@ web3_service = DefaultWeb3Service(config, wallet_provider=custom_wallet)
76
73
  {
77
74
  "strategy": {
78
75
  "wallet_type": "local",
79
- "main_wallet": {"address": "0x...", "wallet_type": "local"},
80
- "strategy_wallet": {"address": "0x..."}
76
+ "main_wallet": { "address": "0x...", "wallet_type": "local" },
77
+ "strategy_wallet": { "address": "0x..." }
81
78
  }
82
79
  }
83
80
  ```
@@ -12,7 +12,7 @@ from pathlib import Path
12
12
 
13
13
  from loguru import logger
14
14
 
15
- from wayfinder_paths.core.config import StrategyJobConfig, load_config_from_env
15
+ from wayfinder_paths.core.config import StrategyJobConfig
16
16
  from wayfinder_paths.core.engine.manifest import load_manifest, validate_manifest
17
17
  from wayfinder_paths.core.engine.StrategyJob import StrategyJob
18
18
 
@@ -21,7 +21,6 @@ def load_strategy(
21
21
  strategy_name: str,
22
22
  *,
23
23
  strategy_config: dict | None = None,
24
- simulation: bool = False,
25
24
  api_key: str | None = None,
26
25
  ):
27
26
  """
@@ -30,7 +29,6 @@ def load_strategy(
30
29
  Args:
31
30
  strategy_name: Name of the strategy to load (directory name in strategies/)
32
31
  strategy_config: Configuration dict for the strategy
33
- simulation: Enable simulation mode for testing
34
32
  api_key: Optional API key for service account authentication
35
33
 
36
34
  Returns:
@@ -59,36 +57,45 @@ def load_strategy(
59
57
  module = __import__(module_path, fromlist=[class_name])
60
58
  strategy_class = getattr(module, class_name)
61
59
 
62
- return strategy_class(
63
- config=strategy_config, simulation=simulation, api_key=api_key
64
- )
60
+ return strategy_class(config=strategy_config, api_key=api_key)
65
61
 
66
62
 
67
63
  def load_config(
68
64
  config_path: str | None = None, strategy_name: str | None = None
69
65
  ) -> StrategyJobConfig:
70
66
  """
71
- Load configuration from file or environment
67
+ Load configuration from config.json file
72
68
 
73
69
  Args:
74
- config_path: Optional path to config file
70
+ config_path: Path to config file (defaults to "config.json")
75
71
  strategy_name: Optional strategy name for per-strategy wallet lookup
76
72
 
77
73
  Returns:
78
74
  StrategyJobConfig instance
75
+
76
+ Raises:
77
+ FileNotFoundError: If config file does not exist
79
78
  """
80
- if config_path and Path(config_path).exists():
81
- logger.info(f"Loading config from {config_path}")
82
- with open(config_path) as f:
83
- config_data = json.load(f)
84
- return StrategyJobConfig.from_dict(config_data, strategy_name=strategy_name)
85
- else:
86
- logger.info("Loading config from environment variables")
87
- config = load_config_from_env()
88
- if strategy_name:
89
- config.strategy_config["_strategy_name"] = strategy_name
90
- config.__post_init__()
91
- return config
79
+ # Default to config.json if not provided
80
+ if not config_path:
81
+ config_path = "config.json"
82
+
83
+ config_file = Path(config_path)
84
+ if not config_file.exists():
85
+ raise FileNotFoundError(
86
+ f"Config file not found: {config_path}. "
87
+ "Please create config.json (see wayfinder_paths/config.example.json for template)"
88
+ )
89
+
90
+ logger.info(f"Loading config from {config_path}")
91
+ with open(config_file) as f:
92
+ config_data = json.load(f)
93
+
94
+ config = StrategyJobConfig.from_dict(config_data, strategy_name=strategy_name)
95
+ if strategy_name:
96
+ config.strategy_config["_strategy_name"] = strategy_name
97
+ config.__post_init__()
98
+ return config
92
99
 
93
100
 
94
101
  async def run_strategy(
@@ -96,7 +103,6 @@ async def run_strategy(
96
103
  config_path: str | None = None,
97
104
  action: str = "run",
98
105
  manifest_path: str | None = None,
99
- simulation: bool = False,
100
106
  **kwargs,
101
107
  ):
102
108
  """
@@ -159,9 +165,7 @@ async def run_strategy(
159
165
  module_path, class_name = manifest.entrypoint.rsplit(".", 1)
160
166
  module = __import__(module_path, fromlist=[class_name])
161
167
  strategy_class = getattr(module, class_name)
162
- strategy = strategy_class(
163
- config=config.strategy_config, simulation=simulation
164
- )
168
+ strategy = strategy_class(config=config.strategy_config)
165
169
  logger.info(
166
170
  f"Loaded strategy from manifest: {strategy_name_for_wallet or 'unnamed'}"
167
171
  )
@@ -169,7 +173,6 @@ async def run_strategy(
169
173
  strategy = load_strategy(
170
174
  strategy_name,
171
175
  strategy_config=config.strategy_config,
172
- simulation=simulation,
173
176
  )
174
177
  logger.info(f"Loaded strategy: {strategy.name}")
175
178
 
@@ -326,7 +329,7 @@ def main():
326
329
  help="Path to strategy manifest YAML (alternative to strategy name)",
327
330
  )
328
331
  parser.add_argument(
329
- "--config", help="Path to config file (defaults to environment variables)"
332
+ "--config", help="Path to config file (defaults to config.json)"
330
333
  )
331
334
  parser.add_argument(
332
335
  "--action",
@@ -372,11 +375,6 @@ def main():
372
375
  "--duration", type=int, help="Duration in seconds for script action"
373
376
  )
374
377
  parser.add_argument("--debug", action="store_true", help="Enable debug logging")
375
- parser.add_argument(
376
- "--simulation",
377
- action="store_true",
378
- help="Run in simulation mode (no real transactions)",
379
- )
380
378
  parser.add_argument(
381
379
  "--wallet-id",
382
380
  help="Wallet ID for policy rendering (replaces FORMAT_WALLET_ID in policies)",
@@ -401,7 +399,6 @@ def main():
401
399
  gas_token_amount=args.gas_token_amount,
402
400
  interval=args.interval,
403
401
  duration=args.duration,
404
- simulation=args.simulation,
405
402
  wallet_id=getattr(args, "wallet_id", None),
406
403
  )
407
404
  )
@@ -15,27 +15,6 @@ def to_keystore_json(private_key_hex: str, password: str):
15
15
  return Account.encrypt(private_key_hex, password)
16
16
 
17
17
 
18
- def write_env(rows: list[dict[str, str]], out_dir: Path) -> None:
19
- with open(out_dir / ".env.example", "w") as f:
20
- if rows:
21
- label_to_wallet = {r.get("label"): r for r in rows if r.get("label")}
22
- main_w = (
23
- label_to_wallet.get("main") or label_to_wallet.get("default") or rows[0]
24
- )
25
- strategy_w = label_to_wallet.get("strategy")
26
-
27
- f.write("RPC_URL=https://rpc.ankr.com/eth\n")
28
- # Back-compat defaults
29
- f.write(f"PRIVATE_KEY={main_w['private_key_hex']}\n")
30
- f.write(f"FROM_ADDRESS={main_w['address']}\n")
31
- # Explicit main/strategy variables
32
- f.write(f"MAIN_WALLET_ADDRESS={main_w['address']}\n")
33
- if strategy_w:
34
- f.write(f"STRATEGY_WALLET_ADDRESS={strategy_w['address']}\n")
35
- # Optional: expose strategy private key for local dev only
36
- f.write(f"PRIVATE_KEY_STRATEGY={strategy_w['private_key_hex']}\n")
37
-
38
-
39
18
  def main():
40
19
  parser = argparse.ArgumentParser(description="Generate local dev wallets")
41
20
  parser.add_argument(
@@ -48,7 +27,7 @@ def main():
48
27
  "--out-dir",
49
28
  type=Path,
50
29
  default=Path("."),
51
- help="Output directory for wallets.json (and .env/keystore)",
30
+ help="Output directory for wallets.json (and keystore files)",
52
31
  )
53
32
  parser.add_argument(
54
33
  "--keystore-password",
@@ -161,9 +140,6 @@ def main():
161
140
  ks_path.write_text(json.dumps(ks))
162
141
  index += 1
163
142
 
164
- # Convenience outputs
165
- write_env(rows, args.out_dir)
166
-
167
143
 
168
144
  if __name__ == "__main__":
169
145
  main()
@@ -55,7 +55,6 @@ async def _run(args: argparse.Namespace) -> int:
55
55
  "main_wallet": main_wallet,
56
56
  "strategy_wallet": strategy_wallet,
57
57
  },
58
- simulation=args.simulation,
59
58
  )
60
59
 
61
60
  await s.setup()
@@ -101,7 +100,6 @@ def main() -> int:
101
100
  )
102
101
  p.add_argument("--main-wallet-label", default="main")
103
102
  p.add_argument("--strategy-wallet-label", default="basis_trading_strategy")
104
- p.add_argument("--simulation", action="store_true")
105
103
 
106
104
  sub = p.add_subparsers(dest="command", required=True)
107
105
 
@@ -8,7 +8,6 @@ from __future__ import annotations
8
8
 
9
9
  import asyncio
10
10
  import json
11
- import os
12
11
  import time
13
12
  from datetime import UTC, datetime
14
13
  from decimal import ROUND_DOWN, Decimal
@@ -1007,5 +1006,4 @@ class BasisSnapshotMixin:
1007
1006
  )
1008
1007
  if isinstance(val, str) and val.strip():
1009
1008
  return val.strip()
1010
- env = os.getenv("BASIS_SNAPSHOT_PATH")
1011
- return env.strip() if isinstance(env, str) and env.strip() else None
1009
+ return None