poly-web3 0.0.4__py3-none-any.whl → 0.0.5__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.
@@ -1,113 +1,113 @@
1
- # -*- coding = utf-8 -*-
2
- # @Time: 2025/12/21 19:45
3
- # @Author: PinBar
4
- # @Site:
5
- # @File: build.py
6
- # @Software: PyCharm
7
- from typing import Union, Optional
8
-
9
-
10
- def string_to_bytes(value: str, size: Optional[int] = None) -> bytes:
11
- data = value.encode("utf-8")
12
- if size is None:
13
- return data
14
- if len(data) > size:
15
- raise ValueError(f"Size overflow: given {len(data)}, max {size}")
16
- return data + b"\x00" * (size - len(data))
17
-
18
-
19
- def keccak256(data: bytes) -> bytes:
20
- try:
21
- from eth_hash.auto import keccak
22
-
23
- return keccak(data)
24
- except Exception:
25
- try:
26
- import sha3 # pysha3
27
-
28
- k = sha3.keccak_256()
29
- except Exception:
30
- from Crypto.Hash import keccak # pycryptodome
31
-
32
- k = keccak.new(digest_bits=256)
33
- k.update(data)
34
- return k.digest()
35
-
36
-
37
- def to_checksum_address(addr_bytes: bytes) -> str:
38
- hex_addr = addr_bytes.hex()
39
- hash_hex = keccak256(hex_addr.encode()).hex()
40
- checksum = "".join(
41
- ch.upper() if int(hash_hex[i], 16) >= 8 else ch for i, ch in enumerate(hex_addr)
42
- )
43
- return "0x" + checksum
44
-
45
-
46
- def derive_proxy_wallet(address: str, proxy_factory: str, bytecode_hash: str) -> str:
47
- addr_bytes = bytes.fromhex(address[2:] if address.startswith("0x") else address)
48
- factory_bytes = bytes.fromhex(
49
- proxy_factory[2:] if proxy_factory.startswith("0x") else proxy_factory
50
- )
51
- bytecode_bytes = bytes.fromhex(
52
- bytecode_hash[2:] if bytecode_hash.startswith("0x") else bytecode_hash
53
- )
54
- salt = keccak256(
55
- addr_bytes
56
- ) # equivalent to keccak256(encodePacked(["address"], [address]))
57
- data = b"\xff" + factory_bytes + salt + bytecode_bytes
58
- create2_hash = keccak256(data)
59
- return to_checksum_address(create2_hash[12:]) # last 20 bytes
60
-
61
-
62
- HexLike = Union[str, bytes, int]
63
-
64
-
65
- def create_struct_hash(
66
- from_addr: str,
67
- to: str,
68
- data: str,
69
- tx_fee: HexLike,
70
- gas_price: HexLike,
71
- gas_limit: HexLike,
72
- nonce: HexLike,
73
- relay_hub_address: str,
74
- relay_address: str,
75
- ) -> str:
76
- def to_bytes(hex_like: HexLike, size: int | None = None) -> bytes:
77
- if isinstance(hex_like, int):
78
- length = (
79
- size if size is not None else max(1, (hex_like.bit_length() + 7) // 8)
80
- )
81
- return hex_like.to_bytes(length, "big")
82
- if isinstance(hex_like, bytes):
83
- return hex_like.rjust(size, b"\x00") if size else hex_like
84
- if isinstance(hex_like, str):
85
- if hex_like.startswith("0x"):
86
- raw = bytes.fromhex(hex_like[2:])
87
- return raw.rjust(size, b"\x00") if size else raw
88
- if hex_like.isdigit(): # numeric string -> int
89
- num = int(hex_like)
90
- length = (
91
- size if size is not None else max(1, (num.bit_length() + 7) // 8)
92
- )
93
- return num.to_bytes(length, "big")
94
- raw = hex_like.encode() # fallback ascii
95
- return raw.rjust(size, b"\x00") if size else raw
96
- raise TypeError("Unsupported type for to_bytes")
97
-
98
- relay_hub_prefix = to_bytes("rlx:")
99
- data_to_hash = b"".join(
100
- [
101
- relay_hub_prefix,
102
- to_bytes(from_addr),
103
- to_bytes(to),
104
- to_bytes(data),
105
- to_bytes(tx_fee, size=32),
106
- to_bytes(gas_price, size=32),
107
- to_bytes(gas_limit, size=32),
108
- to_bytes(nonce, size=32),
109
- to_bytes(relay_hub_address),
110
- to_bytes(relay_address),
111
- ]
112
- )
113
- return "0x" + keccak256(data_to_hash).hex()
1
+ # -*- coding = utf-8 -*-
2
+ # @Time: 2025/12/21 19:45
3
+ # @Author: PinBar
4
+ # @Site:
5
+ # @File: build.py
6
+ # @Software: PyCharm
7
+ from typing import Union, Optional
8
+
9
+
10
+ def string_to_bytes(value: str, size: Optional[int] = None) -> bytes:
11
+ data = value.encode("utf-8")
12
+ if size is None:
13
+ return data
14
+ if len(data) > size:
15
+ raise ValueError(f"Size overflow: given {len(data)}, max {size}")
16
+ return data + b"\x00" * (size - len(data))
17
+
18
+
19
+ def keccak256(data: bytes) -> bytes:
20
+ try:
21
+ from eth_hash.auto import keccak
22
+
23
+ return keccak(data)
24
+ except Exception:
25
+ try:
26
+ import sha3 # pysha3
27
+
28
+ k = sha3.keccak_256()
29
+ except Exception:
30
+ from Crypto.Hash import keccak # pycryptodome
31
+
32
+ k = keccak.new(digest_bits=256)
33
+ k.update(data)
34
+ return k.digest()
35
+
36
+
37
+ def to_checksum_address(addr_bytes: bytes) -> str:
38
+ hex_addr = addr_bytes.hex()
39
+ hash_hex = keccak256(hex_addr.encode()).hex()
40
+ checksum = "".join(
41
+ ch.upper() if int(hash_hex[i], 16) >= 8 else ch for i, ch in enumerate(hex_addr)
42
+ )
43
+ return "0x" + checksum
44
+
45
+
46
+ def derive_proxy_wallet(address: str, proxy_factory: str, bytecode_hash: str) -> str:
47
+ addr_bytes = bytes.fromhex(address[2:] if address.startswith("0x") else address)
48
+ factory_bytes = bytes.fromhex(
49
+ proxy_factory[2:] if proxy_factory.startswith("0x") else proxy_factory
50
+ )
51
+ bytecode_bytes = bytes.fromhex(
52
+ bytecode_hash[2:] if bytecode_hash.startswith("0x") else bytecode_hash
53
+ )
54
+ salt = keccak256(
55
+ addr_bytes
56
+ ) # equivalent to keccak256(encodePacked(["address"], [address]))
57
+ data = b"\xff" + factory_bytes + salt + bytecode_bytes
58
+ create2_hash = keccak256(data)
59
+ return to_checksum_address(create2_hash[12:]) # last 20 bytes
60
+
61
+
62
+ HexLike = Union[str, bytes, int]
63
+
64
+
65
+ def create_struct_hash(
66
+ from_addr: str,
67
+ to: str,
68
+ data: str,
69
+ tx_fee: HexLike,
70
+ gas_price: HexLike,
71
+ gas_limit: HexLike,
72
+ nonce: HexLike,
73
+ relay_hub_address: str,
74
+ relay_address: str,
75
+ ) -> str:
76
+ def to_bytes(hex_like: HexLike, size: int | None = None) -> bytes:
77
+ if isinstance(hex_like, int):
78
+ length = (
79
+ size if size is not None else max(1, (hex_like.bit_length() + 7) // 8)
80
+ )
81
+ return hex_like.to_bytes(length, "big")
82
+ if isinstance(hex_like, bytes):
83
+ return hex_like.rjust(size, b"\x00") if size else hex_like
84
+ if isinstance(hex_like, str):
85
+ if hex_like.startswith("0x"):
86
+ raw = bytes.fromhex(hex_like[2:])
87
+ return raw.rjust(size, b"\x00") if size else raw
88
+ if hex_like.isdigit(): # numeric string -> int
89
+ num = int(hex_like)
90
+ length = (
91
+ size if size is not None else max(1, (num.bit_length() + 7) // 8)
92
+ )
93
+ return num.to_bytes(length, "big")
94
+ raw = hex_like.encode() # fallback ascii
95
+ return raw.rjust(size, b"\x00") if size else raw
96
+ raise TypeError("Unsupported type for to_bytes")
97
+
98
+ relay_hub_prefix = to_bytes("rlx:")
99
+ data_to_hash = b"".join(
100
+ [
101
+ relay_hub_prefix,
102
+ to_bytes(from_addr),
103
+ to_bytes(to),
104
+ to_bytes(data),
105
+ to_bytes(tx_fee, size=32),
106
+ to_bytes(gas_price, size=32),
107
+ to_bytes(gas_limit, size=32),
108
+ to_bytes(nonce, size=32),
109
+ to_bytes(relay_hub_address),
110
+ to_bytes(relay_address),
111
+ ]
112
+ )
113
+ return "0x" + keccak256(data_to_hash).hex()
@@ -1,48 +1,48 @@
1
- # -*- coding = utf-8 -*-
2
- # @Time: 2025/12/21 19:43
3
- # @Author: PinBar
4
- # @Site:
5
- # @File: hash_message.py
6
- # @Software: PyCharm
7
- from eth_hash.auto import keccak
8
-
9
-
10
- def _is_hex(s: str) -> bool:
11
- return isinstance(s, str) and s.startswith("0x")
12
-
13
-
14
- def _hex_to_bytes(h: str) -> bytes:
15
- # 假设是 0x 前缀
16
- return bytes.fromhex(h[2:])
17
-
18
-
19
- def _size_of_message(value) -> int:
20
- # 对齐 viem: hex -> (len-2)/2 向上取整, bytes -> len
21
- if _is_hex(value):
22
- return (len(value) - 2 + 1) // 2
23
- return len(value)
24
-
25
-
26
- def _to_prefixed_message(message) -> bytes:
27
- if isinstance(message, str):
28
- msg_bytes = message.encode("utf-8")
29
- elif isinstance(message, dict) and "raw" in message:
30
- raw = message["raw"]
31
- if isinstance(raw, str):
32
- # viem 这里直接当作 hex 字符串使用
33
- msg_bytes = _hex_to_bytes(raw)
34
- else:
35
- # raw 可以是 list[int], bytes, bytearray
36
- msg_bytes = bytes(raw)
37
- else:
38
- raise TypeError("Unsupported SignableMessage")
39
-
40
- prefix = f"\x19Ethereum Signed Message:\n{len(msg_bytes)}".encode("utf-8")
41
- return prefix + msg_bytes
42
-
43
-
44
- def hash_message(message, to: str = "hex"):
45
- digest = keccak(_to_prefixed_message(message))
46
- if to == "bytes":
47
- return digest
48
- return "0x" + digest.hex()
1
+ # -*- coding = utf-8 -*-
2
+ # @Time: 2025/12/21 19:43
3
+ # @Author: PinBar
4
+ # @Site:
5
+ # @File: hash_message.py
6
+ # @Software: PyCharm
7
+ from eth_hash.auto import keccak
8
+
9
+
10
+ def _is_hex(s: str) -> bool:
11
+ return isinstance(s, str) and s.startswith("0x")
12
+
13
+
14
+ def _hex_to_bytes(h: str) -> bytes:
15
+ # 假设是 0x 前缀
16
+ return bytes.fromhex(h[2:])
17
+
18
+
19
+ def _size_of_message(value) -> int:
20
+ # 对齐 viem: hex -> (len-2)/2 向上取整, bytes -> len
21
+ if _is_hex(value):
22
+ return (len(value) - 2 + 1) // 2
23
+ return len(value)
24
+
25
+
26
+ def _to_prefixed_message(message) -> bytes:
27
+ if isinstance(message, str):
28
+ msg_bytes = message.encode("utf-8")
29
+ elif isinstance(message, dict) and "raw" in message:
30
+ raw = message["raw"]
31
+ if isinstance(raw, str):
32
+ # viem 这里直接当作 hex 字符串使用
33
+ msg_bytes = _hex_to_bytes(raw)
34
+ else:
35
+ # raw 可以是 list[int], bytes, bytearray
36
+ msg_bytes = bytes(raw)
37
+ else:
38
+ raise TypeError("Unsupported SignableMessage")
39
+
40
+ prefix = f"\x19Ethereum Signed Message:\n{len(msg_bytes)}".encode("utf-8")
41
+ return prefix + msg_bytes
42
+
43
+
44
+ def hash_message(message, to: str = "hex"):
45
+ digest = keccak(_to_prefixed_message(message))
46
+ if to == "bytes":
47
+ return digest
48
+ return "0x" + digest.hex()
@@ -1,57 +1,57 @@
1
- # -*- coding = utf-8 -*-
2
- # @Time: 2025/12/21 19:44
3
- # @Author: PinBar
4
- # @Site:
5
- # @File: secp256k1.py
6
- # @Software: PyCharm
7
- from eth_keys import keys
8
- from eth_utils import decode_hex
9
-
10
- SECP256K1_N = int(
11
- "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16
12
- )
13
- HALF_N = SECP256K1_N // 2
14
-
15
-
16
- def sign(hash_hex: str, priv_hex: str):
17
- msg = decode_hex(hash_hex)
18
- priv = keys.PrivateKey(decode_hex(priv_hex))
19
- sig = priv.sign_msg_hash(msg)
20
- r, s, v = sig.r, sig.s, sig.v
21
-
22
- if s > HALF_N:
23
- s = SECP256K1_N - s
24
- # Ethereum recovery id flips when s is negated
25
- v ^= 1
26
-
27
- return r, s, v
28
-
29
-
30
- def int_to_hex(n: int, size: int = 32) -> str:
31
- # size 是字节数,32 字节 -> 64 个 hex 字符
32
- return "0x" + n.to_bytes(size, "big").hex()
33
-
34
-
35
- def hex_to_int(h: str) -> int:
36
- return int(h, 16)
37
-
38
-
39
- def serialize_signature(r: str, s: str, v=None, yParity=None, to="hex"):
40
- # 计算 yParity_
41
- if yParity in (0, 1):
42
- yParity_ = yParity
43
- elif v is not None and (v in (27, 28) or v >= 35):
44
- yParity_ = 1 if (v % 2 == 0) else 0
45
- else:
46
- raise ValueError("Invalid `v` or `yParity` value")
47
-
48
- # toCompactHex: r||s (各 32 字节)
49
- r_int = hex_to_int(r)
50
- s_int = hex_to_int(s)
51
- compact = r_int.to_bytes(32, "big").hex() + s_int.to_bytes(32, "big").hex()
52
-
53
- signature_hex = "0x" + compact + ("1b" if yParity_ == 0 else "1c")
54
-
55
- if to == "hex":
56
- return signature_hex
57
- return bytes.fromhex(signature_hex[2:])
1
+ # -*- coding = utf-8 -*-
2
+ # @Time: 2025/12/21 19:44
3
+ # @Author: PinBar
4
+ # @Site:
5
+ # @File: secp256k1.py
6
+ # @Software: PyCharm
7
+ from eth_keys import keys
8
+ from eth_utils import decode_hex
9
+
10
+ SECP256K1_N = int(
11
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16
12
+ )
13
+ HALF_N = SECP256K1_N // 2
14
+
15
+
16
+ def sign(hash_hex: str, priv_hex: str):
17
+ msg = decode_hex(hash_hex)
18
+ priv = keys.PrivateKey(decode_hex(priv_hex))
19
+ sig = priv.sign_msg_hash(msg)
20
+ r, s, v = sig.r, sig.s, sig.v
21
+
22
+ if s > HALF_N:
23
+ s = SECP256K1_N - s
24
+ # Ethereum recovery id flips when s is negated
25
+ v ^= 1
26
+
27
+ return r, s, v
28
+
29
+
30
+ def int_to_hex(n: int, size: int = 32) -> str:
31
+ # size 是字节数,32 字节 -> 64 个 hex 字符
32
+ return "0x" + n.to_bytes(size, "big").hex()
33
+
34
+
35
+ def hex_to_int(h: str) -> int:
36
+ return int(h, 16)
37
+
38
+
39
+ def serialize_signature(r: str, s: str, v=None, yParity=None, to="hex"):
40
+ # 计算 yParity_
41
+ if yParity in (0, 1):
42
+ yParity_ = yParity
43
+ elif v is not None and (v in (27, 28) or v >= 35):
44
+ yParity_ = 1 if (v % 2 == 0) else 0
45
+ else:
46
+ raise ValueError("Invalid `v` or `yParity` value")
47
+
48
+ # toCompactHex: r||s (各 32 字节)
49
+ r_int = hex_to_int(r)
50
+ s_int = hex_to_int(s)
51
+ compact = r_int.to_bytes(32, "big").hex() + s_int.to_bytes(32, "big").hex()
52
+
53
+ signature_hex = "0x" + compact + ("1b" if yParity_ == 0 else "1c")
54
+
55
+ if to == "hex":
56
+ return signature_hex
57
+ return bytes.fromhex(signature_hex[2:])
@@ -1,9 +1,9 @@
1
- # -*- coding = utf-8 -*-
2
- # @Time: 2025-12-27 16:07:53
3
- # @Author: PinBar
4
- # @Site:
5
- # @File: __init__.py
6
- # @Software: PyCharm
7
- from poly_web3.web3_service.eoa_service import EOAWeb3Service
8
- from poly_web3.web3_service.proxy_service import ProxyWeb3Service
9
- from poly_web3.web3_service.safe_service import SafeWeb3Service
1
+ # -*- coding = utf-8 -*-
2
+ # @Time: 2025-12-27 16:07:53
3
+ # @Author: PinBar
4
+ # @Site:
5
+ # @File: __init__.py
6
+ # @Software: PyCharm
7
+ from poly_web3.web3_service.eoa_service import EOAWeb3Service
8
+ from poly_web3.web3_service.proxy_service import ProxyWeb3Service
9
+ from poly_web3.web3_service.safe_service import SafeWeb3Service