arc-devkit 0.4.4__tar.gz → 0.4.6__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 (62) hide show
  1. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/PKG-INFO +1 -1
  2. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/__init__.py +2 -1
  3. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/agents/async_monitor.py +15 -13
  4. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/agents/monitor_agent.py +11 -5
  5. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/agents/payment_agent.py +23 -15
  6. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/analytics/portfolio.py +7 -9
  7. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/api/routes/agents.py +1 -1
  8. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/cli/flat.py +8 -10
  9. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/copilot/agent.py +5 -2
  10. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/debugger/tx_analyzer.py +11 -6
  11. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/deploy/deployer.py +2 -3
  12. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/events/listener.py +1 -3
  13. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit.egg-info/PKG-INFO +1 -1
  14. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/pyproject.toml +1 -1
  15. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_agents.py +1 -4
  16. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_analytics.py +12 -11
  17. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_api.py +4 -4
  18. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_async_agents.py +21 -15
  19. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_cli.py +29 -12
  20. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_contracts.py +8 -10
  21. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_debugger.py +3 -8
  22. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_deploy.py +3 -2
  23. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_events.py +29 -7
  24. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_usdc.py +4 -3
  25. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/README.md +0 -0
  26. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/agents/__init__.py +0 -0
  27. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/agents/async_base.py +0 -0
  28. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/agents/base_agent.py +0 -0
  29. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/analytics/__init__.py +0 -0
  30. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/api/__init__.py +0 -0
  31. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/api/main.py +0 -0
  32. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/api/routes/__init__.py +0 -0
  33. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/api/routes/copilot.py +0 -0
  34. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/api/routes/debugger.py +0 -0
  35. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/cli/__init__.py +0 -0
  36. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/cli/commands/__init__.py +0 -0
  37. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/cli/commands/agent.py +0 -0
  38. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/cli/commands/copilot.py +0 -0
  39. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/cli/commands/debug.py +0 -0
  40. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/cli/main.py +0 -0
  41. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/config.py +0 -0
  42. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/contracts/__init__.py +0 -0
  43. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/contracts/loader.py +0 -0
  44. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/copilot/__init__.py +0 -0
  45. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/core/__init__.py +0 -0
  46. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/core/connection.py +0 -0
  47. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/core/gas.py +0 -0
  48. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/core/wallet.py +0 -0
  49. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/debugger/__init__.py +0 -0
  50. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/deploy/__init__.py +0 -0
  51. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/events/__init__.py +0 -0
  52. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/usdc/__init__.py +0 -0
  53. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit/usdc/token.py +0 -0
  54. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit.egg-info/SOURCES.txt +0 -0
  55. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit.egg-info/dependency_links.txt +0 -0
  56. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit.egg-info/entry_points.txt +0 -0
  57. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit.egg-info/requires.txt +0 -0
  58. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/arc_devkit.egg-info/top_level.txt +0 -0
  59. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/setup.cfg +0 -0
  60. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_connection.py +0 -0
  61. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_copilot.py +0 -0
  62. {arc_devkit-0.4.4 → arc_devkit-0.4.6}/tests/test_integration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arc-devkit
3
- Version: 0.4.4
3
+ Version: 0.4.6
4
4
  Summary: Plataforma open source de ferramentas para desenvolvedores da Arc blockchain (Circle)
5
5
  Author-email: Jeielsantosdev <jeielsantos.ti@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,7 @@
1
1
  """Arc DevKit — Developer tools for the Arc blockchain by Circle."""
2
2
 
3
- from importlib.metadata import PackageNotFoundError, version as _version
3
+ from importlib.metadata import PackageNotFoundError
4
+ from importlib.metadata import version as _version
4
5
 
5
6
  try:
6
7
  __version__ = _version("arc-devkit")
@@ -3,7 +3,7 @@
3
3
  import asyncio
4
4
  import json
5
5
  import logging
6
- from collections.abc import AsyncIterator, Callable, Coroutine
6
+ from collections.abc import AsyncIterator, Callable
7
7
  from pathlib import Path
8
8
  from typing import Any, cast
9
9
 
@@ -99,10 +99,12 @@ class AsyncMonitorAgent(AsyncBaseAgent):
99
99
  if self._state_file:
100
100
  try:
101
101
  self._state_file.write_text(
102
- json.dumps({
103
- "balances": {k: str(v) for k, v in self._last_balances.items()},
104
- "last_erc20_block": self._last_erc20_block,
105
- })
102
+ json.dumps(
103
+ {
104
+ "balances": {k: str(v) for k, v in self._last_balances.items()},
105
+ "last_erc20_block": self._last_erc20_block,
106
+ }
107
+ )
106
108
  )
107
109
  except Exception as exc:
108
110
  logger.warning("Failed to save state: %s", exc)
@@ -159,7 +161,11 @@ class AsyncMonitorAgent(AsyncBaseAgent):
159
161
 
160
162
  direction = "credit" if recipient in self._watched_lower else "debit"
161
163
  address = next(
162
- (a for a in self._watched if a.lower() == (recipient if direction == "credit" else sender)),
164
+ (
165
+ a
166
+ for a in self._watched
167
+ if a.lower() == (recipient if direction == "credit" else sender)
168
+ ),
163
169
  "",
164
170
  )
165
171
 
@@ -182,9 +188,7 @@ class AsyncMonitorAgent(AsyncBaseAgent):
182
188
  async def get_balance(self) -> dict: # type: ignore[override]
183
189
  resultado = {}
184
190
  for addr in self._watched:
185
- wei = await self._acall_rpc(
186
- self._w3.eth.get_balance, cast(ChecksumAddress, addr)
187
- )
191
+ wei = await self._acall_rpc(self._w3.eth.get_balance, cast(ChecksumAddress, addr))
188
192
  resultado[addr] = {
189
193
  "address": addr,
190
194
  "balance_wei": str(wei),
@@ -215,9 +219,7 @@ class AsyncMonitorAgent(AsyncBaseAgent):
215
219
 
216
220
  if self._usdc_contract and self._last_erc20_block == 0:
217
221
  try:
218
- self._last_erc20_block = await self._acall_rpc(
219
- lambda: self._w3.eth.block_number
220
- )
222
+ self._last_erc20_block = await self._acall_rpc(lambda: self._w3.eth.block_number)
221
223
  except Exception:
222
224
  pass
223
225
 
@@ -295,7 +297,7 @@ class AsyncMonitorAgent(AsyncBaseAgent):
295
297
  break
296
298
  try:
297
299
  event = await asyncio.wait_for(queue.get(), timeout=1.0)
298
- except asyncio.TimeoutError:
300
+ except TimeoutError:
299
301
  continue # re-check task.done() on next iteration
300
302
  yield event
301
303
  count += 1
@@ -111,10 +111,12 @@ class MonitorAgent(BaseAgent):
111
111
  if self._state_file:
112
112
  try:
113
113
  self._state_file.write_text(
114
- json.dumps({
115
- "balances": {k: str(v) for k, v in self._last_balances.items()},
116
- "last_erc20_block": self._last_erc20_block,
117
- })
114
+ json.dumps(
115
+ {
116
+ "balances": {k: str(v) for k, v in self._last_balances.items()},
117
+ "last_erc20_block": self._last_erc20_block,
118
+ }
119
+ )
118
120
  )
119
121
  except Exception as exc:
120
122
  logger.warning("Failed to save state: %s", exc)
@@ -170,7 +172,11 @@ class MonitorAgent(BaseAgent):
170
172
 
171
173
  direction = "credit" if recipient in self._watched_lower else "debit"
172
174
  address = next(
173
- (a for a in self._watched if a.lower() == (recipient if direction == "credit" else sender)),
175
+ (
176
+ a
177
+ for a in self._watched
178
+ if a.lower() == (recipient if direction == "credit" else sender)
179
+ ),
174
180
  "",
175
181
  )
176
182
 
@@ -77,7 +77,7 @@ class PaymentAgent(BaseAgent):
77
77
 
78
78
  def _build_usdc_signed_tx(self, to: str, amount: Decimal) -> tuple:
79
79
  """Build and sign a USDC ERC-20 transfer tx; return (signed, gas_limit)."""
80
- from arc_devkit.usdc.token import _ERC20_ABI, USDC_MULTIPLIER, USDC_ARC_TESTNET_ADDRESS
80
+ from arc_devkit.usdc.token import _ERC20_ABI, USDC_ARC_TESTNET_ADDRESS, USDC_MULTIPLIER
81
81
 
82
82
  usdc_address = Web3.to_checksum_address(USDC_ARC_TESTNET_ADDRESS)
83
83
  contract = self._w3.eth.contract(address=usdc_address, abi=_ERC20_ABI)
@@ -85,12 +85,15 @@ class PaymentAgent(BaseAgent):
85
85
  nonce = self._w3.eth.get_transaction_count(cast(ChecksumAddress, self._address))
86
86
 
87
87
  tx = contract.functions.transfer(to, atomic).build_transaction(
88
- cast(TxParams, {
89
- "from": self._address,
90
- "nonce": nonce,
91
- "gasPrice": self._w3.eth.gas_price,
92
- "chainId": self._w3.eth.chain_id,
93
- })
88
+ cast(
89
+ TxParams,
90
+ {
91
+ "from": self._address,
92
+ "nonce": nonce,
93
+ "gasPrice": self._w3.eth.gas_price,
94
+ "chainId": self._w3.eth.chain_id,
95
+ },
96
+ )
94
97
  )
95
98
  gas_limit = self._estimate_gas(cast(TxParams, tx))
96
99
  tx["gas"] = gas_limit
@@ -137,15 +140,20 @@ class PaymentAgent(BaseAgent):
137
140
  else:
138
141
  value_wei = self._w3.to_wei(amount_usdc, "ether")
139
142
  nonce = self._w3.eth.get_transaction_count(cast(ChecksumAddress, self._address))
140
- tx_base = cast(TxParams, {
141
- "from": self._address,
142
- "to": destinatario,
143
- "value": value_wei,
144
- "nonce": nonce,
145
- "chainId": self._w3.eth.chain_id,
146
- })
143
+ tx_base = cast(
144
+ TxParams,
145
+ {
146
+ "from": self._address,
147
+ "to": destinatario,
148
+ "value": value_wei,
149
+ "nonce": nonce,
150
+ "chainId": self._w3.eth.chain_id,
151
+ },
152
+ )
147
153
  gas_limit = self._estimate_gas(tx_base)
148
- tx = cast(TxParams, {**tx_base, "gas": gas_limit, "gasPrice": self._w3.eth.gas_price})
154
+ tx = cast(
155
+ TxParams, {**tx_base, "gas": gas_limit, "gasPrice": self._w3.eth.gas_price}
156
+ )
149
157
  signed = self._w3.eth.account.sign_transaction(tx, self._private_key)
150
158
  self.log("Transaction signed successfully.")
151
159
 
@@ -3,7 +3,7 @@
3
3
  import json
4
4
  import logging
5
5
  from dataclasses import dataclass
6
- from datetime import datetime, timezone
6
+ from datetime import UTC, datetime
7
7
  from decimal import Decimal
8
8
  from pathlib import Path
9
9
  from typing import Any, Literal
@@ -34,11 +34,11 @@ class PortfolioSnapshot:
34
34
  """Point-in-time view of a wallet's portfolio on Arc."""
35
35
 
36
36
  address: str
37
- native_balance: Decimal # ARC (18 decimals, converted to ether)
38
- usdc_balance: Decimal | None # USDC (6 decimals); None if contract unavailable
39
- nonce: int # total txs ever sent from this address
37
+ native_balance: Decimal # ARC (18 decimals, converted to ether)
38
+ usdc_balance: Decimal | None # USDC (6 decimals); None if contract unavailable
39
+ nonce: int # total txs ever sent from this address
40
40
  recent_txs: list[TransactionSummary]
41
- blocks_scanned: int # actual number of blocks inspected
41
+ blocks_scanned: int # actual number of blocks inspected
42
42
  blocks_from: int
43
43
  blocks_to: int
44
44
  activity_score: ActivityLevel
@@ -151,7 +151,7 @@ class PortfolioAnalyzer:
151
151
  history_file = store / f"{safe_addr}.jsonl"
152
152
 
153
153
  record = self.to_dict(snapshot)
154
- record["timestamp"] = datetime.now(tz=timezone.utc).isoformat()
154
+ record["timestamp"] = datetime.now(tz=UTC).isoformat()
155
155
 
156
156
  with history_file.open("a", encoding="utf-8") as f:
157
157
  f.write(json.dumps(record) + "\n")
@@ -289,9 +289,7 @@ class PortfolioAnalyzer:
289
289
  except Exception:
290
290
  pass
291
291
 
292
- value_arc = Decimal(
293
- str(self._w3.from_wei(tx.get("value", 0), "ether"))
294
- )
292
+ value_arc = Decimal(str(self._w3.from_wei(tx.get("value", 0), "ether")))
295
293
 
296
294
  results.append(
297
295
  TransactionSummary(
@@ -180,7 +180,7 @@ async def monitor_ws(
180
180
  try:
181
181
  event = await asyncio.wait_for(queue.get(), timeout=1.0)
182
182
  await websocket.send_json(event)
183
- except asyncio.TimeoutError:
183
+ except TimeoutError:
184
184
  # Send a heartbeat ping to detect dead connections
185
185
  try:
186
186
  await websocket.send_json({"event_type": "ping"})
@@ -193,6 +193,7 @@ def balance(
193
193
  checksum = _validate_address(address)
194
194
  w3 = get_web3()
195
195
  from eth_typing import ChecksumAddress as _CA
196
+
196
197
  saldo = Decimal(str(w3.from_wei(w3.eth.get_balance(cast(_CA, checksum)), "ether")))
197
198
  nonce = w3.eth.get_transaction_count(cast(_CA, checksum))
198
199
 
@@ -397,9 +398,7 @@ def debug_batch(
397
398
  console.print(summary_table)
398
399
  ok = sum(1 for r in results if r.get("status") == "success")
399
400
  fail = len(results) - ok
400
- console.print(
401
- f"\n[green]✓ {ok} succeeded[/green] [red]✗ {fail} failed[/red]"
402
- )
401
+ console.print(f"\n[green]✓ {ok} succeeded[/green] [red]✗ {fail} failed[/red]")
403
402
 
404
403
 
405
404
  @app.command()
@@ -426,9 +425,12 @@ def codegen(
426
425
  )
427
426
 
428
427
  with console.status("DevCopilot generating code...", spinner="dots"):
429
- resposta = DevCopilot().ask(prompt)
428
+ resposta = DevCopilot(max_tokens=8000).ask(prompt)
430
429
 
431
430
  match = re.search(r"```python\s*(.*?)```", resposta, re.DOTALL)
431
+ if not match:
432
+ # Fallback: grab everything after ```python even if closing fence is missing
433
+ match = re.search(r"```python\s*(.*)", resposta, re.DOTALL)
432
434
  codigo = match.group(1).strip() if match else None
433
435
  explicacao = re.sub(r"```python.*?```", "", resposta, flags=re.DOTALL).strip()
434
436
 
@@ -970,9 +972,7 @@ def portfolio_report(
970
972
  except SystemExit:
971
973
  continue
972
974
 
973
- with console.status(
974
- f"Analyzing [cyan]{checksum[:10]}...[/cyan]", spinner="dots"
975
- ):
975
+ with console.status(f"Analyzing [cyan]{checksum[:10]}...[/cyan]", spinner="dots"):
976
976
  snapshot = analyzer.analyze(checksum, scan_blocks=blocks)
977
977
 
978
978
  data = analyzer.to_dict(snapshot)
@@ -981,9 +981,7 @@ def portfolio_report(
981
981
 
982
982
  score_color = _SCORE_COLOR[snapshot.activity_score]
983
983
  score_icon = _SCORE_ICON[snapshot.activity_score]
984
- usdc_str = (
985
- f"{snapshot.usdc_balance:.4f}" if snapshot.usdc_balance is not None else "N/A"
986
- )
984
+ usdc_str = f"{snapshot.usdc_balance:.4f}" if snapshot.usdc_balance is not None else "N/A"
987
985
 
988
986
  report_table.add_row(
989
987
  label or "—",
@@ -71,6 +71,7 @@ class DevCopilot:
71
71
  extra_context: str | None = None,
72
72
  model: str | None = None,
73
73
  offline: bool = False,
74
+ max_tokens: int | None = None,
74
75
  ) -> None:
75
76
  """
76
77
  Args:
@@ -79,10 +80,12 @@ class DevCopilot:
79
80
  model: Model override (default: ANTHROPIC_MODEL from .env).
80
81
  offline: When True, return a mock response without calling the API.
81
82
  Useful for local tests and CI environments without an API key.
83
+ max_tokens: Override the default MAX_TOKENS limit for this instance.
82
84
  """
83
85
  self._offline = offline
84
86
  self._client = anthropic.Anthropic(api_key=settings.anthropic_api_key)
85
87
  self.model = model or settings.anthropic_model
88
+ self._max_tokens = max_tokens if max_tokens is not None else self.MAX_TOKENS
86
89
  self._history: list[dict] = []
87
90
  self._cache: dict[str, tuple[str, float]] = {} # key → (response, timestamp)
88
91
 
@@ -147,7 +150,7 @@ class DevCopilot:
147
150
 
148
151
  message = self._client.messages.create(
149
152
  model=self.model,
150
- max_tokens=self.MAX_TOKENS,
153
+ max_tokens=self._max_tokens,
151
154
  system=self._system,
152
155
  messages=cast(list[MessageParam], list(self._history)),
153
156
  )
@@ -197,7 +200,7 @@ class DevCopilot:
197
200
 
198
201
  with self._client.messages.stream(
199
202
  model=self.model,
200
- max_tokens=self.MAX_TOKENS,
203
+ max_tokens=self._max_tokens,
201
204
  system=self._system,
202
205
  messages=cast(list[MessageParam], self._history),
203
206
  ) as stream:
@@ -13,8 +13,8 @@ from arc_devkit.core.connection import get_web3
13
13
  logger = logging.getLogger(__name__)
14
14
 
15
15
  # Solidity revert selectors
16
- _REVERT_SELECTOR = bytes.fromhex("08c379a0") # Error(string)
17
- _PANIC_SELECTOR = bytes.fromhex("4e487b71") # Panic(uint256)
16
+ _REVERT_SELECTOR = bytes.fromhex("08c379a0") # Error(string)
17
+ _PANIC_SELECTOR = bytes.fromhex("4e487b71") # Panic(uint256)
18
18
 
19
19
  _PANIC_CODES: dict[int, str] = {
20
20
  0x00: "Generic compiler-inserted panic",
@@ -164,6 +164,7 @@ class TxAnalyzer:
164
164
  self._w3 = w3
165
165
  elif rpc_url:
166
166
  from web3.middleware import ExtraDataToPOAMiddleware
167
+
167
168
  _w3 = Web3(Web3.HTTPProvider(rpc_url, request_kwargs={"timeout": 10}))
168
169
  _w3.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0)
169
170
  self._w3 = _w3
@@ -252,9 +253,7 @@ class TxAnalyzer:
252
253
  summary = copilot.ask(prompt)
253
254
  except Exception as exc:
254
255
  logger.warning("AI analysis unavailable: %s", exc)
255
- summary = (
256
- f"Status: {status_str} | Gas used: {gas_used} | Cost: {cost_decimal} USDC"
257
- )
256
+ summary = f"Status: {status_str} | Gas used: {gas_used} | Cost: {cost_decimal} USDC"
258
257
  if revert_reason:
259
258
  summary += f" | Revert: {revert_reason}"
260
259
 
@@ -364,7 +363,13 @@ class TxAnalyzer:
364
363
  normalized[k] = str(v)
365
364
  elif isinstance(v, (list, tuple)):
366
365
  normalized[k] = [
367
- ("0x" + x.hex() if isinstance(x, bytes) else str(x) if isinstance(x, int) else x)
366
+ (
367
+ "0x" + x.hex()
368
+ if isinstance(x, bytes)
369
+ else str(x)
370
+ if isinstance(x, int)
371
+ else x
372
+ )
368
373
  for x in v
369
374
  ]
370
375
  else:
@@ -1,7 +1,7 @@
1
1
  """Contract compilation and deployment for Arc DevKit."""
2
2
 
3
3
  import logging
4
- from dataclasses import dataclass, field
4
+ from dataclasses import dataclass
5
5
  from decimal import Decimal
6
6
  from pathlib import Path
7
7
  from typing import Any
@@ -214,8 +214,7 @@ class ContractDeployer:
214
214
  if key is None:
215
215
  available = [k.split(":")[-1] for k in compiled]
216
216
  raise ValueError(
217
- f"Contract '{contract_name}' not found. "
218
- f"Available: {', '.join(available)}"
217
+ f"Contract '{contract_name}' not found. Available: {', '.join(available)}"
219
218
  )
220
219
 
221
220
  abi = compiled[key]["abi"]
@@ -50,9 +50,7 @@ class EventListener:
50
50
 
51
51
  self._contract = None
52
52
  if self._contract_address and self._abi:
53
- self._contract = self._w3.eth.contract(
54
- address=self._contract_address, abi=self._abi
55
- )
53
+ self._contract = self._w3.eth.contract(address=self._contract_address, abi=self._abi)
56
54
 
57
55
  # ------------------------------------------------------------------
58
56
  # Registration
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arc-devkit
3
- Version: 0.4.4
3
+ Version: 0.4.6
4
4
  Summary: Plataforma open source de ferramentas para desenvolvedores da Arc blockchain (Circle)
5
5
  Author-email: Jeielsantosdev <jeielsantos.ti@gmail.com>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "arc-devkit"
7
- version = "0.4.4"
7
+ version = "0.4.6"
8
8
  description = "Plataforma open source de ferramentas para desenvolvedores da Arc blockchain (Circle)"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -94,7 +94,6 @@ class TestPaymentAgent:
94
94
  assert result == 21_000
95
95
 
96
96
  def test_wait_for_receipt_returns_receipt(self, mock_web3):
97
- import time
98
97
 
99
98
  receipt = {"status": 1, "gasUsed": 21_000}
100
99
  mock_web3.eth.get_transaction_receipt.return_value = receipt
@@ -235,9 +234,7 @@ class TestPaymentAgent:
235
234
  from arc_devkit.agents.payment_agent import PaymentAgent
236
235
 
237
236
  agent = PaymentAgent(private_key="0x" + "a" * 64)
238
- with patch("time.sleep") as mock_sleep, patch(
239
- "time.time", side_effect=[0.0, 1.0, 2.0]
240
- ):
237
+ with patch("time.sleep") as mock_sleep, patch("time.time", side_effect=[0.0, 1.0, 2.0]):
241
238
  result = agent._wait_for_receipt(b"\xde\xad", timeout=10)
242
239
  assert result == receipt
243
240
  mock_sleep.assert_called_once()
@@ -4,9 +4,6 @@ import json
4
4
  from decimal import Decimal
5
5
  from unittest.mock import MagicMock, patch
6
6
 
7
- import pytest
8
-
9
-
10
7
  # ---------------------------------------------------------------------------
11
8
  # Helpers
12
9
  # ---------------------------------------------------------------------------
@@ -358,7 +355,7 @@ class TestPortfolioCLI:
358
355
 
359
356
  class TestBalanceHistory:
360
357
  def _make_snapshot(self, address="0x" + "a" * 40, tx_count=3):
361
- from arc_devkit.analytics.portfolio import ActivityLevel, PortfolioSnapshot
358
+ from arc_devkit.analytics.portfolio import PortfolioSnapshot
362
359
 
363
360
  return PortfolioSnapshot(
364
361
  address=address,
@@ -390,7 +387,7 @@ class TestBalanceHistory:
390
387
  analyzer.save_snapshot(snap, history_dir=tmp_path)
391
388
  analyzer.save_snapshot(snap, history_dir=tmp_path)
392
389
  path = tmp_path / f"{snap.address.lower()}.jsonl"
393
- lines = [l for l in path.read_text().splitlines() if l.strip()]
390
+ lines = [line for line in path.read_text().splitlines() if line.strip()]
394
391
  assert len(lines) == 2
395
392
 
396
393
  def test_save_snapshot_includes_timestamp(self, tmp_path):
@@ -442,11 +439,11 @@ class TestBalanceHistory:
442
439
 
443
440
  from arc_devkit.cli.flat import app
444
441
 
445
- monkeypatch.setattr(
446
- "arc_devkit.analytics.portfolio._HISTORY_DIR", tmp_path / "history"
447
- )
442
+ monkeypatch.setattr("arc_devkit.analytics.portfolio._HISTORY_DIR", tmp_path / "history")
448
443
  runner = CliRunner()
449
- with patch("arc_devkit.analytics.portfolio.PortfolioAnalyzer.load_history", return_value=[]):
444
+ with patch(
445
+ "arc_devkit.analytics.portfolio.PortfolioAnalyzer.load_history", return_value=[]
446
+ ):
450
447
  result = runner.invoke(app, ["portfolio", "history", "0x" + "a" * 40])
451
448
  assert result.exit_code == 0
452
449
  assert "No history" in result.output or "history" in result.output.lower()
@@ -457,9 +454,13 @@ class TestBalanceHistory:
457
454
 
458
455
  from arc_devkit.cli.flat import app
459
456
 
460
- records = [{"native_balance": "1.5", "timestamp": "2026-01-01T00:00:00+00:00", "tx_count": 2}]
457
+ records = [
458
+ {"native_balance": "1.5", "timestamp": "2026-01-01T00:00:00+00:00", "tx_count": 2}
459
+ ]
461
460
  runner = CliRunner()
462
- with patch("arc_devkit.analytics.portfolio.PortfolioAnalyzer.load_history", return_value=records):
461
+ with patch(
462
+ "arc_devkit.analytics.portfolio.PortfolioAnalyzer.load_history", return_value=records
463
+ ):
463
464
  result = runner.invoke(app, ["portfolio", "history", "0x" + "a" * 40, "--json"])
464
465
  assert result.exit_code == 0
465
466
  data = json.loads(result.output)
@@ -130,9 +130,7 @@ def test_estimate_gas_sem_to_retorna_422(client):
130
130
 
131
131
  def test_estimate_gas_bad_address_returns_400(client):
132
132
  with patch("arc_devkit.core.gas.estimate_transfer", side_effect=Exception("bad addr")):
133
- resp = client.get(
134
- "/debug/estimate", params={"to": "bad", "amount": 1.0}
135
- )
133
+ resp = client.get("/debug/estimate", params={"to": "bad", "amount": 1.0})
136
134
  assert resp.status_code == 400
137
135
 
138
136
 
@@ -244,7 +242,9 @@ def test_payment_execute_error_returns_400(client):
244
242
 
245
243
 
246
244
  def test_payment_500_on_unexpected_exception(client, mock_web3):
247
- with patch("arc_devkit.agents.payment_agent.PaymentAgent.execute", side_effect=Exception("boom")):
245
+ with patch(
246
+ "arc_devkit.agents.payment_agent.PaymentAgent.execute", side_effect=Exception("boom")
247
+ ):
248
248
  resp = client.post(
249
249
  "/agents/payment",
250
250
  json={
@@ -1,11 +1,9 @@
1
1
  """Tests for AsyncBaseAgent, AsyncMonitorAgent, and WebSocket endpoint."""
2
2
 
3
- import asyncio
4
3
  from unittest.mock import AsyncMock, MagicMock, patch
5
4
 
6
5
  import pytest
7
6
 
8
-
9
7
  # ---------------------------------------------------------------------------
10
8
  # Helpers
11
9
  # ---------------------------------------------------------------------------
@@ -146,8 +144,8 @@ async def test_async_monitor_callback_fired_on_change():
146
144
  w3.from_wei.return_value = "1.0"
147
145
  # First call seeds the initial balance, second detects a change
148
146
  w3.eth.get_balance.side_effect = [
149
- _MOCK_BALANCE, # initial seed in execute()
150
- _MOCK_BALANCE * 2, # change detected on first iteration
147
+ _MOCK_BALANCE, # initial seed in execute()
148
+ _MOCK_BALANCE * 2, # change detected on first iteration
151
149
  ]
152
150
  monitor._w3 = w3
153
151
 
@@ -235,11 +233,16 @@ async def test_async_monitor_event_stream_yields():
235
233
 
236
234
  def test_websocket_monitor_accepts_connection():
237
235
  """WebSocket /agents/monitor/{address} must accept and send heartbeat pings."""
238
- from arc_devkit.api.main import app
239
236
  from fastapi.testclient import TestClient
240
237
 
241
- with patch("arc_devkit.core.connection.get_web3", return_value=_mock_w3()), \
242
- patch("arc_devkit.agents.async_monitor.AsyncMonitorAgent.execute", new_callable=AsyncMock) as mock_exec:
238
+ from arc_devkit.api.main import app
239
+
240
+ with (
241
+ patch("arc_devkit.core.connection.get_web3", return_value=_mock_w3()),
242
+ patch(
243
+ "arc_devkit.agents.async_monitor.AsyncMonitorAgent.execute", new_callable=AsyncMock
244
+ ) as mock_exec,
245
+ ):
243
246
  mock_exec.return_value = {"status": "done", "iterations": 0}
244
247
 
245
248
  client = TestClient(app)
@@ -258,10 +261,14 @@ def test_async_monitor_state_file_loaded(tmp_path):
258
261
  import json
259
262
 
260
263
  state = tmp_path / "state.json"
261
- state.write_text(json.dumps({
262
- "balances": {_ADDRESS: "5000000000000000000"},
263
- "last_erc20_block": 42,
264
- }))
264
+ state.write_text(
265
+ json.dumps(
266
+ {
267
+ "balances": {_ADDRESS: "5000000000000000000"},
268
+ "last_erc20_block": 42,
269
+ }
270
+ )
271
+ )
265
272
 
266
273
  with patch("arc_devkit.core.connection.get_web3", return_value=_mock_w3()):
267
274
  from arc_devkit.agents.async_monitor import AsyncMonitorAgent
@@ -331,8 +338,7 @@ async def test_async_monitor_webhook_called(tmp_path, respx_mock=None):
331
338
  resp.raise_for_status = MagicMock()
332
339
  return resp
333
340
 
334
- with patch("httpx.AsyncClient.post", fake_post), \
335
- patch("asyncio.sleep", new_callable=AsyncMock):
341
+ with patch("httpx.AsyncClient.post", fake_post), patch("asyncio.sleep", new_callable=AsyncMock):
336
342
  await monitor.execute(max_iterations=1)
337
343
 
338
344
  assert len(events_sent) == 1
@@ -345,7 +351,7 @@ async def test_async_monitor_webhook_called(tmp_path, respx_mock=None):
345
351
 
346
352
 
347
353
  def test_copilot_offline_ask_returns_mock(mock_anthropic):
348
- from arc_devkit.copilot.agent import DevCopilot, _OFFLINE_RESPONSE
354
+ from arc_devkit.copilot.agent import _OFFLINE_RESPONSE, DevCopilot
349
355
 
350
356
  copilot = DevCopilot(offline=True)
351
357
  assert copilot.ask("What is Arc?") == _OFFLINE_RESPONSE
@@ -353,7 +359,7 @@ def test_copilot_offline_ask_returns_mock(mock_anthropic):
353
359
 
354
360
 
355
361
  def test_copilot_offline_stream_returns_mock(mock_anthropic):
356
- from arc_devkit.copilot.agent import DevCopilot, _OFFLINE_RESPONSE
362
+ from arc_devkit.copilot.agent import _OFFLINE_RESPONSE, DevCopilot
357
363
 
358
364
  copilot = DevCopilot(offline=True)
359
365
  result = "".join(copilot.ask_stream("What is Arc?"))
@@ -1,12 +1,9 @@
1
1
  """Unit tests for arc_devkit.cli.flat — arc CLI commands."""
2
2
 
3
3
  import json
4
- import tempfile
5
4
  from decimal import Decimal
6
- from pathlib import Path
7
- from unittest.mock import MagicMock, patch
5
+ from unittest.mock import patch
8
6
 
9
- import pytest
10
7
  from typer.testing import CliRunner
11
8
 
12
9
  from arc_devkit.cli.flat import app
@@ -172,7 +169,6 @@ class TestWallet:
172
169
 
173
170
  class TestConfig:
174
171
  def test_config_set_and_get(self, tmp_path, monkeypatch):
175
- env_file = tmp_path / ".env"
176
172
  monkeypatch.chdir(tmp_path)
177
173
 
178
174
  # set
@@ -224,7 +220,9 @@ class TestHistory:
224
220
  def test_history_json_output(self, tmp_path, monkeypatch):
225
221
  history_file = tmp_path / "history.json"
226
222
  history_file.write_text(
227
- json.dumps([{"type": "debug", "tx_hash": "0x" + "a" * 64, "timestamp": "2026-06-21T10:00:00"}])
223
+ json.dumps(
224
+ [{"type": "debug", "tx_hash": "0x" + "a" * 64, "timestamp": "2026-06-21T10:00:00"}]
225
+ )
228
226
  )
229
227
  monkeypatch.setattr("arc_devkit.cli.flat._HISTORY_FILE", history_file)
230
228
  result = runner.invoke(app, ["history", "--json"])
@@ -236,7 +234,15 @@ class TestHistory:
236
234
  def test_history_table_output(self, tmp_path, monkeypatch):
237
235
  history_file = tmp_path / "history.json"
238
236
  history_file.write_text(
239
- json.dumps([{"type": "portfolio", "address": "0x" + "a" * 40, "timestamp": "2026-06-21T10:00:00"}])
237
+ json.dumps(
238
+ [
239
+ {
240
+ "type": "portfolio",
241
+ "address": "0x" + "a" * 40,
242
+ "timestamp": "2026-06-21T10:00:00",
243
+ }
244
+ ]
245
+ )
240
246
  )
241
247
  monkeypatch.setattr("arc_devkit.cli.flat._HISTORY_FILE", history_file)
242
248
  result = runner.invoke(app, ["history"])
@@ -277,7 +283,10 @@ class TestDebugCommand:
277
283
  "summary": "OK",
278
284
  "custo_usdc": "0.0001",
279
285
  "revert_reason": None,
280
- "decoded_input": {"function": "transfer", "args": {"to": "0xf...", "amount": "100"}},
286
+ "decoded_input": {
287
+ "function": "transfer",
288
+ "args": {"to": "0xf...", "amount": "100"},
289
+ },
281
290
  "error": None,
282
291
  "suggestion": "",
283
292
  "raw_data": {},
@@ -353,7 +362,9 @@ class TestSendCommand:
353
362
  "raw_transaction": "0xdeadbeef",
354
363
  "nota": "Transaction signed.",
355
364
  }
356
- with patch("arc_devkit.agents.payment_agent.PaymentAgent.execute", return_value=signed_result):
365
+ with patch(
366
+ "arc_devkit.agents.payment_agent.PaymentAgent.execute", return_value=signed_result
367
+ ):
357
368
  result = runner.invoke(
358
369
  app,
359
370
  ["send", "0x" + "b" * 40, "1.0", "--token", "native", "--json"],
@@ -377,7 +388,9 @@ class TestSendCommand:
377
388
  "raw_transaction": "0xcafebabe",
378
389
  "nota": "USDC transfer signed.",
379
390
  }
380
- with patch("arc_devkit.agents.payment_agent.PaymentAgent.execute", return_value=signed_result):
391
+ with patch(
392
+ "arc_devkit.agents.payment_agent.PaymentAgent.execute", return_value=signed_result
393
+ ):
381
394
  result = runner.invoke(
382
395
  app,
383
396
  ["send", "0x" + "b" * 40, "5.0", "--token", "usdc", "--json"],
@@ -402,7 +415,9 @@ class TestSendCommand:
402
415
  "raw_transaction": "0xdeadbeef01020304050607080910111213",
403
416
  "nota": "Transaction signed.",
404
417
  }
405
- with patch("arc_devkit.agents.payment_agent.PaymentAgent.execute", return_value=signed_result):
418
+ with patch(
419
+ "arc_devkit.agents.payment_agent.PaymentAgent.execute", return_value=signed_result
420
+ ):
406
421
  result = runner.invoke(app, ["send", "0x" + "b" * 40, "2.0"])
407
422
 
408
423
  assert result.exit_code == 0
@@ -421,7 +436,9 @@ class TestSendCommand:
421
436
  "tx_hash": "0x" + "de" * 32,
422
437
  "aviso": "Timeout waiting for receipt.",
423
438
  }
424
- with patch("arc_devkit.agents.payment_agent.PaymentAgent.execute", return_value=sent_result):
439
+ with patch(
440
+ "arc_devkit.agents.payment_agent.PaymentAgent.execute", return_value=sent_result
441
+ ):
425
442
  result = runner.invoke(app, ["send", "0x" + "b" * 40, "3.0", "--token", "usdc"])
426
443
 
427
444
  assert result.exit_code == 0
@@ -3,11 +3,10 @@
3
3
  import json
4
4
  import tempfile
5
5
  from pathlib import Path
6
- from unittest.mock import MagicMock, patch
6
+ from unittest.mock import MagicMock
7
7
 
8
8
  import pytest
9
9
 
10
-
11
10
  # ---------------------------------------------------------------------------
12
11
  # load_abi
13
12
  # ---------------------------------------------------------------------------
@@ -15,9 +14,7 @@ import pytest
15
14
 
16
15
  class TestLoadAbi:
17
16
  def _write_json(self, data: object, suffix: str = ".json") -> Path:
18
- f = tempfile.NamedTemporaryFile(
19
- mode="w", suffix=suffix, delete=False, encoding="utf-8"
20
- )
17
+ f = tempfile.NamedTemporaryFile(mode="w", suffix=suffix, delete=False, encoding="utf-8")
21
18
  json.dump(data, f)
22
19
  f.flush()
23
20
  return Path(f.name)
@@ -79,9 +76,10 @@ class TestCallView:
79
76
  assert result == "USDC"
80
77
 
81
78
  def test_checksum_applied_to_address(self):
82
- from arc_devkit.contracts.loader import call_view
83
79
  from web3 import Web3
84
80
 
81
+ from arc_devkit.contracts.loader import call_view
82
+
85
83
  w3 = self._w3_with_result(0)
86
84
  abi: list = []
87
85
  call_view(abi, "0x" + "a" * 40, "balanceOf", w3=w3)
@@ -153,7 +151,9 @@ class TestDecodeEvents:
153
151
 
154
152
  w3 = MagicMock()
155
153
  decoded_log = MagicMock()
156
- decoded_log.__getitem__ = lambda self, k: {"args": {"from": "0xa", "to": "0xb", "value": 100}}[k]
154
+ decoded_log.__getitem__ = lambda self, k: {
155
+ "args": {"from": "0xa", "to": "0xb", "value": 100}
156
+ }[k]
157
157
  w3.eth.contract.return_value.events.__getitem__.return_value.return_value.process_receipt.return_value = [
158
158
  {"args": {"from": "0xa", "to": "0xb", "value": 100}}
159
159
  ]
@@ -180,8 +180,6 @@ class TestDecodeEvents:
180
180
  from arc_devkit.contracts.loader import decode_events
181
181
 
182
182
  w3 = MagicMock()
183
- w3.eth.contract.return_value.events.__getitem__.return_value.return_value.process_receipt.return_value = (
184
- []
185
- )
183
+ w3.eth.contract.return_value.events.__getitem__.return_value.return_value.process_receipt.return_value = []
186
184
  result = decode_events({}, [], "Transfer", "0x" + "a" * 40, w3=w3)
187
185
  assert result == []
@@ -2,12 +2,8 @@
2
2
 
3
3
  import json
4
4
  import tempfile
5
- from decimal import Decimal
6
5
  from unittest.mock import MagicMock, patch
7
6
 
8
- import pytest
9
-
10
-
11
7
  # ---------------------------------------------------------------------------
12
8
  # Helpers
13
9
  # ---------------------------------------------------------------------------
@@ -115,9 +111,10 @@ class TestDecodeRevertBytes:
115
111
  assert "42" in result
116
112
 
117
113
  def test_custom_error_no_args(self):
118
- from arc_devkit.debugger.tx_analyzer import decode_revert_bytes
119
114
  from web3 import Web3
120
115
 
116
+ from arc_devkit.debugger.tx_analyzer import decode_revert_bytes
117
+
121
118
  abi = [{"type": "error", "name": "Unauthorized", "inputs": []}]
122
119
  selector = Web3.keccak(text="Unauthorized()")[:4]
123
120
  result = decode_revert_bytes(selector, abi=abi)
@@ -323,9 +320,7 @@ class TestDebugCLI:
323
320
  from arc_devkit.cli.flat import app
324
321
 
325
322
  runner = CliRunner()
326
- result = runner.invoke(
327
- app, ["debug", "0x" + "a" * 64, "--abi", "nonexistent.json"]
328
- )
323
+ result = runner.invoke(app, ["debug", "0x" + "a" * 64, "--abi", "nonexistent.json"])
329
324
  assert result.exit_code != 0
330
325
 
331
326
  def test_debug_batch_from_txt_file(self, mock_anthropic):
@@ -1,6 +1,5 @@
1
1
  """Unit tests for arc_devkit.deploy.deployer.ContractDeployer."""
2
2
 
3
- from decimal import Decimal
4
3
  from unittest.mock import MagicMock, patch
5
4
 
6
5
  import pytest
@@ -162,7 +161,9 @@ class TestContractDeployer:
162
161
 
163
162
  def test_deploy_from_source_raises_import_error_without_solcx(self, tmp_path):
164
163
  sol_file = tmp_path / "Token.sol"
165
- sol_file.write_text("// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\ncontract Token {}")
164
+ sol_file.write_text(
165
+ "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\ncontract Token {}"
166
+ )
166
167
 
167
168
  d = self._deployer()
168
169
  with patch.dict("sys.modules", {"solcx": None}):
@@ -100,7 +100,7 @@ class TestEventListenerPoll:
100
100
  log = _make_log(block_number=101)
101
101
  w3 = _make_w3(current_block=101, logs=[log])
102
102
  el = EventListener(w3=w3, from_block=100)
103
- events = el.poll()
103
+ el.poll()
104
104
  w3.eth.get_logs.assert_called_once()
105
105
  call_params = w3.eth.get_logs.call_args[0][0]
106
106
  assert call_params["fromBlock"] == 100
@@ -127,7 +127,14 @@ class TestEventListenerPoll:
127
127
  received: list = []
128
128
 
129
129
  def fake_decode(self_log):
130
- return {"event": "Transfer", "address": "0x...", "args": {}, "block_number": 1, "tx_hash": None, "log_index": 0}
130
+ return {
131
+ "event": "Transfer",
132
+ "address": "0x...",
133
+ "args": {},
134
+ "block_number": 1,
135
+ "tx_hash": None,
136
+ "log_index": 0,
137
+ }
131
138
 
132
139
  with patch.object(EventListener, "_decode_log", side_effect=fake_decode):
133
140
  el.on("Transfer", lambda e: received.append(e))
@@ -182,9 +189,18 @@ class TestEventListenerPoll:
182
189
 
183
190
  received: list = []
184
191
  bad_cb = MagicMock(side_effect=RuntimeError("boom"))
185
- good_cb = lambda e: received.append(e)
186
192
 
187
- fake_event = {"event": "Transfer", "address": "0x", "args": {}, "block_number": 1, "tx_hash": None, "log_index": 0}
193
+ def good_cb(e):
194
+ received.append(e)
195
+
196
+ fake_event = {
197
+ "event": "Transfer",
198
+ "address": "0x",
199
+ "args": {},
200
+ "block_number": 1,
201
+ "tx_hash": None,
202
+ "log_index": 0,
203
+ }
188
204
  with patch.object(EventListener, "_decode_log", return_value=fake_event):
189
205
  el.on("Transfer", bad_cb)
190
206
  el.on("Transfer", good_cb)
@@ -227,7 +243,9 @@ class TestDecodeLog:
227
243
  "transactionHash": bytes.fromhex("ab" * 32),
228
244
  "logIndex": 0,
229
245
  }.get(k, default)
230
- contract_mock.events.__getitem__.return_value.return_value.process_log.return_value = decoded
246
+ contract_mock.events.__getitem__.return_value.return_value.process_log.return_value = (
247
+ decoded
248
+ )
231
249
  w3.eth.contract.return_value = contract_mock
232
250
 
233
251
  el = EventListener(contract_address=addr, abi=abi, w3=w3)
@@ -245,7 +263,9 @@ class TestDecodeLog:
245
263
 
246
264
  w3 = _make_w3()
247
265
  contract_mock = MagicMock()
248
- contract_mock.events.__getitem__.return_value.return_value.process_log.side_effect = Exception("bad log")
266
+ contract_mock.events.__getitem__.return_value.return_value.process_log.side_effect = (
267
+ Exception("bad log")
268
+ )
249
269
  w3.eth.contract.return_value = contract_mock
250
270
 
251
271
  el = EventListener(contract_address=addr, abi=abi, w3=w3)
@@ -275,7 +295,9 @@ class TestDecodeLog:
275
295
  w3 = _make_w3()
276
296
  contract_mock = MagicMock()
277
297
  # Make event decoding fail so we fall back to raw
278
- contract_mock.events.__getitem__.return_value.return_value.process_log.side_effect = Exception("fail")
298
+ contract_mock.events.__getitem__.return_value.return_value.process_log.side_effect = (
299
+ Exception("fail")
300
+ )
279
301
  w3.eth.contract.return_value = contract_mock
280
302
 
281
303
  el = EventListener(contract_address=addr, abi=abi, w3=w3)
@@ -1,7 +1,7 @@
1
1
  """Unit tests for arc_devkit.usdc.token.USDCToken."""
2
2
 
3
3
  from decimal import Decimal
4
- from unittest.mock import MagicMock, patch
4
+ from unittest.mock import MagicMock
5
5
 
6
6
  # Standard Hardhat test private key — valid secp256k1 key safe for tests
7
7
  _PRIVKEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
@@ -34,7 +34,7 @@ def _make_contract_w3(balance_atomic: int = 0) -> MagicMock:
34
34
 
35
35
  class TestUSDCToken:
36
36
  def _token(self, w3=None, balance_atomic: int = 0, contract_address: str | None = None):
37
- from arc_devkit.usdc.token import USDC_ARC_TESTNET_ADDRESS, USDCToken
37
+ from arc_devkit.usdc.token import USDCToken
38
38
 
39
39
  addr = contract_address or "0x" + "c" * 40
40
40
  w3 = w3 or _make_contract_w3(balance_atomic)
@@ -128,9 +128,10 @@ class TestUSDCToken:
128
128
  # --- contract_address property ---
129
129
 
130
130
  def test_contract_address_property(self):
131
- from arc_devkit.usdc.token import USDCToken
132
131
  from web3 import Web3
133
132
 
133
+ from arc_devkit.usdc.token import USDCToken
134
+
134
135
  addr = "0x" + "d" * 40
135
136
  token = USDCToken(contract_address=addr, w3=_make_contract_w3())
136
137
  assert token.contract_address == Web3.to_checksum_address(addr)
File without changes
File without changes