mm-apt 0.3.3__tar.gz → 0.3.5__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.
@@ -1,5 +1,5 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-apt
3
- Version: 0.3.3
3
+ Version: 0.3.5
4
4
  Requires-Python: >=3.12
5
- Requires-Dist: mm-crypto-utils>=0.3.5
5
+ Requires-Dist: mm-crypto-utils>=0.3.7
@@ -1,10 +1,10 @@
1
1
  [project]
2
2
  name = "mm-apt"
3
- version = "0.3.3"
3
+ version = "0.3.5"
4
4
  description = ""
5
5
  requires-python = ">=3.12"
6
6
  dependencies = [
7
- "mm-crypto-utils>=0.3.5",
7
+ "mm-crypto-utils>=0.3.7",
8
8
  ]
9
9
 
10
10
  [build-system]
@@ -15,7 +15,7 @@ build-backend = "hatchling.build"
15
15
  dev-dependencies = [
16
16
  "pytest~=8.3.5",
17
17
  "pytest-xdist~=3.6.1",
18
- "ruff~=0.11.6",
18
+ "ruff~=0.11.8",
19
19
  "pip-audit~=2.9.0",
20
20
  "bandit~=1.8.3",
21
21
  "mypy~=1.15.0",
@@ -0,0 +1,36 @@
1
+ import re
2
+
3
+ # Maximum allowable Aptos account address value (256 bits)
4
+ MAX_APTOS_ADDRESS = 2**256
5
+
6
+
7
+ def is_valid_address(address: str) -> bool:
8
+ """
9
+ Check if the address is a valid Aptos account address.
10
+
11
+ Requirements:
12
+ - Must be a 32-byte (64 hex characters) string.
13
+ - Must be an entire 64-character hex string, padded with leading zeros as needed.
14
+ - Optional '0x' or '0X' prefix is allowed.
15
+ - Numeric value must be < 2**256.
16
+ """
17
+ # Ensure input is a string
18
+ if not isinstance(address, str):
19
+ return False
20
+
21
+ # Remove optional prefix
22
+ hex_part = address[2:] if address.startswith(("0x", "0X")) else address
23
+
24
+ # Must be exactly 64 hex characters
25
+ if len(hex_part) != 64:
26
+ return False
27
+ if not re.fullmatch(r"[0-9a-fA-F]{64}", hex_part):
28
+ return False
29
+
30
+ # Convert to integer and check range
31
+ try:
32
+ value = int(hex_part, 16)
33
+ except ValueError:
34
+ return False
35
+
36
+ return 0 <= value < MAX_APTOS_ADDRESS
@@ -0,0 +1,12 @@
1
+ from mm_crypto_utils import Nodes, Proxies, retry_with_node_and_proxy
2
+ from mm_std import Result
3
+
4
+ from mm_apt import balance
5
+
6
+
7
+ async def get_balance(
8
+ retries: int, nodes: Nodes, proxies: Proxies, *, account: str, coin_type: str, timeout: float = 5
9
+ ) -> Result[int]:
10
+ return await retry_with_node_and_proxy(
11
+ retries, nodes, proxies, lambda node, proxy: balance.get_balance(node, account, coin_type, timeout, proxy)
12
+ )
@@ -0,0 +1,55 @@
1
+ import pytest
2
+
3
+ from mm_apt.account import is_valid_address
4
+
5
+
6
+ # Helper to generate a full 64-char hex string with a given repeat char
7
+ def full_hex(ch):
8
+ return ch * 64
9
+
10
+
11
+ def test_valid_full_length_addresses():
12
+ # All zeros
13
+ assert is_valid_address("0x" + full_hex("0")) is True
14
+ # Mixed zeros and ones
15
+ assert is_valid_address("0x" + "0" * 63 + "1") is True
16
+ # All Fs (max minus 1)
17
+ assert is_valid_address("0x" + full_hex("f")) is True
18
+ # Uppercase hex
19
+ assert is_valid_address("0X" + full_hex("A")) is True
20
+ # Without prefix
21
+ assert is_valid_address(full_hex("1")) is True
22
+
23
+
24
+ def test_invalid_full_length_addresses():
25
+ # Too short
26
+ short_hex = "0x" + "1" * 63
27
+ assert is_valid_address(short_hex) is False
28
+ # Too long
29
+ long_hex = "0x" + "f" * 65
30
+ assert is_valid_address(long_hex) is False
31
+ # Invalid character
32
+ bad_char = "0x" + "g" + "0" * 63
33
+ assert is_valid_address(bad_char) is False
34
+ # Numeric type
35
+ assert is_valid_address(123) is False
36
+
37
+
38
+ def test_address_out_of_range():
39
+ # Exactly 2**256 is out of range -> 1 followed by 64 zeros in hex is too large (65 hex digits)
40
+ out_of_range = "0x1" + "0" * 64
41
+ # It's invalid by length then by range
42
+ assert is_valid_address(out_of_range) is False
43
+ # Highest valid: 2**256 - 1 -> 64 hex 'f'
44
+ max_valid = "0x" + full_hex("f")
45
+ assert is_valid_address(max_valid) is True
46
+
47
+
48
+ def test_missing_prefix_short_address():
49
+ # Even valid numeric value but missing prefix and not full-length
50
+ assert is_valid_address("1" * 1) is False
51
+ assert is_valid_address("a" * 10) is False
52
+
53
+
54
+ if __name__ == "__main__":
55
+ pytest.main()