mm-strk 0.4.1__tar.gz → 0.4.3__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.
@@ -0,0 +1,14 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(just lint:*)",
5
+ "WebFetch(domain:github.com)",
6
+ "WebFetch(domain:docs.starknet.io)",
7
+ "Bash(curl:*)",
8
+ "WebFetch(domain:www.starknet.io)",
9
+ "WebFetch(domain:www.comparenodes.com)",
10
+ "WebFetch(domain:starknetpy.readthedocs.io)",
11
+ "WebFetch(domain:pypi.org)"
12
+ ]
13
+ }
14
+ }
mm_strk-0.4.3/ADR.md ADDED
@@ -0,0 +1,3 @@
1
+ # Architecture Decision Records
2
+
3
+ Key design decisions for this project. Read this before suggesting changes.
@@ -0,0 +1,19 @@
1
+ # Claude Guidelines
2
+
3
+ ## Critical Guidelines
4
+
5
+ 1. **Always communicate in English** - Regardless of the language the user speaks, always respond in English. All code, comments, and documentation must be in English.
6
+
7
+ 2. **Minimal documentation** - Only add comments/documentation when it simplifies understanding and isn't obvious from the code itself. Keep it strictly relevant and concise.
8
+
9
+ 3. **Critical thinking** - Always critically evaluate user ideas. Users can make mistakes. Think first about whether the user's idea is good before implementing.
10
+
11
+ 4. **Lint after changes** - After making code changes, always run `just lint` to verify code quality and fix any linter issues.
12
+
13
+ 5. **No disabling linter rules** - Never use special disabling comments (like `# noqa`, `# type: ignore`, `# ruff: noqa`, etc.) to turn off linter rules without explicit permission. If you believe a rule should be disabled, ask first.
14
+
15
+ ## Required Reading
16
+
17
+ Before working on this codebase, read these documents:
18
+ 1. `README.md` - Project overview and API
19
+ 2. `ADR.md` - Architectural decisions and rationale
mm_strk-0.4.3/PKG-INFO ADDED
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: mm-strk
3
+ Version: 0.4.3
4
+ Requires-Python: >=3.13
5
+ Requires-Dist: mm-web3~=0.5.7
6
+ Requires-Dist: starknet-py~=0.29.0
7
+ Requires-Dist: typer~=0.21.1
@@ -0,0 +1,72 @@
1
+ # mm-strk
2
+
3
+ Starknet utilities library.
4
+
5
+ **Requires RPC node version 0.9+**
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install mm-strk
11
+ ```
12
+
13
+ ## API
14
+
15
+ ### is_address
16
+
17
+ Validates a Starknet address.
18
+
19
+ ```python
20
+ from mm_strk.account import is_address
21
+
22
+ is_address("0x123abc") # True - minimal form
23
+ is_address("0x0000000000000000000000000000000000000000000000000000000000123abc") # True - full 64-char form
24
+ is_address("invalid") # False
25
+ ```
26
+
27
+ ### get_balance
28
+
29
+ Queries token balance for an address.
30
+
31
+ ```python
32
+ import asyncio
33
+ from mm_strk.balance import get_balance, ETH_ADDRESS_MAINNET, STRK_ADDRESS_MAINNET
34
+
35
+ result = asyncio.run(get_balance(
36
+ rpc_url="https://your-rpc-node.com",
37
+ address="0x123...",
38
+ token=ETH_ADDRESS_MAINNET,
39
+ ))
40
+ if result.is_ok():
41
+ print(result.ok) # balance in wei
42
+ ```
43
+
44
+ Token constants:
45
+ - `ETH_ADDRESS_MAINNET`, `ETH_DECIMALS` (18)
46
+ - `STRK_ADDRESS_MAINNET`, `STRK_DECIMALS` (18)
47
+ - `USDC_ADDRESS_MAINNET`, `USDC_DECIMALS` (6)
48
+ - `USDT_ADDRESS_MAINNET`, `USDT_DECIMALS` (6)
49
+ - `DAI_ADDRESS_MAINNET`, `DAI_DECIMALS` (18)
50
+
51
+ ### address_to_domain
52
+
53
+ Resolves a Starknet address to its Starknet ID domain.
54
+
55
+ ```python
56
+ import asyncio
57
+ from mm_strk.domain import address_to_domain
58
+
59
+ result = asyncio.run(address_to_domain("0x123..."))
60
+ if result.is_ok():
61
+ print(result.ok) # "example.stark" or None if not found
62
+ ```
63
+
64
+ ## CLI
65
+
66
+ ### mm-strk node
67
+
68
+ Check status of Starknet RPC nodes.
69
+
70
+ ```bash
71
+ mm-strk node https://rpc-node-1.com https://rpc-node-2.com
72
+ ```
@@ -1,13 +1,9 @@
1
1
  [project]
2
2
  name = "mm-strk"
3
- version = "0.4.1"
3
+ version = "0.4.3"
4
4
  description = ""
5
5
  requires-python = ">=3.13"
6
- dependencies = [
7
- "mm-cryptocurrency~=0.4.7",
8
- "starknet-py~=0.27.0",
9
- "typer>=0.16.0",
10
- ]
6
+ dependencies = ["mm-web3~=0.5.7", "starknet-py~=0.29.0", "typer~=0.21.1"]
11
7
  [project.scripts]
12
8
  mm-strk = "mm_strk.cli.cli:app"
13
9
 
@@ -17,17 +13,20 @@ requires = ["hatchling"]
17
13
  build-backend = "hatchling.build"
18
14
 
19
15
 
20
- [tool.uv]
21
- dev-dependencies = [
22
- "pytest~=8.4.0",
23
- "pytest-asyncio~=1.0.0",
24
- "pytest-xdist~=3.7.0",
25
- "ruff~=0.11.13",
26
- "pip-audit~=2.9.0",
27
- "bandit~=1.8.3",
28
- "mypy~=1.16.0",
29
- "python-dotenv>=1.1.0",
16
+ [dependency-groups]
17
+ dev = [
18
+ "bandit~=1.9.2",
19
+ "mypy~=1.19.1",
20
+ "pip-audit~=2.10.0",
21
+ "pre-commit~=4.5.1",
22
+ "pytest~=9.0.2",
23
+ "pytest-asyncio~=1.3.0",
24
+ "pytest-xdist~=3.8.0",
25
+ "ruff~=0.14.13",
26
+ "python-dotenv~=1.2.0",
30
27
  ]
28
+
29
+ [tool.uv]
31
30
  override-dependencies = ["pywin32 ; sys_platform == 'win32'"]
32
31
 
33
32
 
@@ -39,5 +39,5 @@ def is_address(address: str) -> bool:
39
39
  return True
40
40
 
41
41
  # Minimal form (no leading zeros)
42
- canonical = hex(value)[2:]
42
+ canonical = f"{value:x}"
43
43
  return hex_part.lower() == canonical
@@ -8,12 +8,16 @@ from starknet_py.net.full_node_client import FullNodeClient
8
8
 
9
9
 
10
10
  class NodeStatus(BaseModel):
11
+ """Starknet node status response."""
12
+
13
+ spec_version: str
11
14
  block_number: int | str
12
15
  chain_id: int | str
13
16
  syncing_status: bool | SyncStatus | str
14
17
 
15
18
 
16
19
  def run(urls: list[str], proxy: str | None) -> None:
20
+ """Check status of Starknet nodes."""
17
21
  if proxy:
18
22
  typer.echo("proxy is not supported yet")
19
23
  raise typer.Exit(code=1)
@@ -29,8 +33,14 @@ async def _run(urls: list[str]) -> None:
29
33
 
30
34
 
31
35
  async def _node_status(url: str) -> NodeStatus:
36
+ """Fetch status from a single node."""
32
37
  client = FullNodeClient(node_url=url)
33
38
 
39
+ try:
40
+ spec_version: str = await client.spec_version()
41
+ except Exception as e:
42
+ spec_version = str(e)
43
+
34
44
  try:
35
45
  block_number: int | str = await client.get_block_number()
36
46
  except Exception as e:
@@ -46,4 +56,4 @@ async def _node_status(url: str) -> NodeStatus:
46
56
  except Exception as e:
47
57
  syncing_status = str(e)
48
58
 
49
- return NodeStatus(block_number=block_number, chain_id=chain_id, syncing_status=syncing_status)
59
+ return NodeStatus(spec_version=spec_version, block_number=block_number, chain_id=chain_id, syncing_status=syncing_status)
@@ -14,7 +14,7 @@ async def address_to_domain(address: str, timeout: float = 5.0, proxy: str | Non
14
14
  return res.to_result_ok(None)
15
15
  if res.is_err():
16
16
  return res.to_result_err()
17
- domain = res.parse_json_body("domain")
17
+ domain = res.parse_json("domain")
18
18
  if domain:
19
19
  return res.to_result_ok(domain)
20
20
  return res.to_result_err("unknown_response")