zhlink 0.1.0__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.
- zhlink-0.1.0/PKG-INFO +212 -0
- zhlink-0.1.0/README.md +200 -0
- zhlink-0.1.0/pyproject.toml +32 -0
- zhlink-0.1.0/setup.cfg +4 -0
- zhlink-0.1.0/tests/test_smoke.py +321 -0
- zhlink-0.1.0/zhlink/__init__.py +36 -0
- zhlink-0.1.0/zhlink/_rawtx_bridge.py +29 -0
- zhlink-0.1.0/zhlink/_vendor/bip39_english.txt +2048 -0
- zhlink-0.1.0/zhlink/_vendor/zhc_rawtx/__init__.py +47 -0
- zhlink-0.1.0/zhlink/_vendor/zhc_rawtx/cli.py +84 -0
- zhlink-0.1.0/zhlink/_vendor/zhc_rawtx/core.py +757 -0
- zhlink-0.1.0/zhlink/_vendor/zhc_rawtx/gasfree.py +569 -0
- zhlink-0.1.0/zhlink/address.py +93 -0
- zhlink-0.1.0/zhlink/api.py +458 -0
- zhlink-0.1.0/zhlink/config.py +86 -0
- zhlink-0.1.0/zhlink/logging_config.py +133 -0
- zhlink-0.1.0/zhlink/mnemonic.py +231 -0
- zhlink-0.1.0/zhlink/rpc.py +1139 -0
- zhlink-0.1.0/zhlink/signer.py +194 -0
- zhlink-0.1.0/zhlink/zeroscan.py +258 -0
- zhlink-0.1.0/zhlink.egg-info/PKG-INFO +212 -0
- zhlink-0.1.0/zhlink.egg-info/SOURCES.txt +23 -0
- zhlink-0.1.0/zhlink.egg-info/dependency_links.txt +1 -0
- zhlink-0.1.0/zhlink.egg-info/requires.txt +4 -0
- zhlink-0.1.0/zhlink.egg-info/top_level.txt +1 -0
zhlink-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zhlink
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Self-contained Python library for ZHCASH addresses, balances, ZHC sends, and USDZ gas-free sends.
|
|
5
|
+
Author: ZHCASH
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: cryptography>=42
|
|
9
|
+
Requires-Dist: httpx==0.28.1
|
|
10
|
+
Requires-Dist: mnemonic==0.21
|
|
11
|
+
Requires-Dist: pycryptodome>=3.20
|
|
12
|
+
|
|
13
|
+
# ZHLink Python Library
|
|
14
|
+
|
|
15
|
+
`zhlink` is a self-contained Python library for ZHCASH.
|
|
16
|
+
|
|
17
|
+
The public API is intentionally small:
|
|
18
|
+
|
|
19
|
+
- create a new ZHC address;
|
|
20
|
+
- check ZHC + USDZ balance;
|
|
21
|
+
- send native ZHC from a private key;
|
|
22
|
+
- send USDZ with admin-paid ZHC gas;
|
|
23
|
+
- optionally read extra ZRC-20 token balances.
|
|
24
|
+
|
|
25
|
+
The raw transaction engine is bundled inside the package. Normal users only
|
|
26
|
+
import `zhlink`.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
Recommended Python:
|
|
31
|
+
|
|
32
|
+
- Python `3.10` or newer is required.
|
|
33
|
+
- Python `3.10` and `3.11` are the safest choices for deployment.
|
|
34
|
+
- Python `3.12` should work.
|
|
35
|
+
- Python `3.9` and older are not supported.
|
|
36
|
+
|
|
37
|
+
From PyPI:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install zhlink
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
From this folder:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
cd /root/wallet/zhlink
|
|
47
|
+
python3 -m venv .venv
|
|
48
|
+
. .venv/bin/activate
|
|
49
|
+
pip install -e .
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
For direct local use without install:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
cd /root/wallet/zhlink
|
|
56
|
+
export PYTHONPATH=/root/wallet/zhlink
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Create Address
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from zhlink import create_address
|
|
63
|
+
|
|
64
|
+
wallet = create_address()
|
|
65
|
+
|
|
66
|
+
print(wallet.address)
|
|
67
|
+
print(wallet.priv_key)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Private keys are generated locally. The library never sends private keys to
|
|
71
|
+
ZeroScan or RPC.
|
|
72
|
+
|
|
73
|
+
## Get Balance
|
|
74
|
+
|
|
75
|
+
By default `get_balance` returns ZHC and USDZ.
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from zhlink import get_balance
|
|
79
|
+
|
|
80
|
+
balance = get_balance("Z...")
|
|
81
|
+
|
|
82
|
+
print(balance["zhc"])
|
|
83
|
+
print(balance["usdz"])
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Extra ZRC-20 tokens can be requested when needed:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from zhlink import get_balance
|
|
90
|
+
|
|
91
|
+
balance = get_balance(
|
|
92
|
+
"Z...",
|
|
93
|
+
tokens={"EDS": "dc71958156a945d3071374521e1a7a42f5ba8038"},
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
print(balance["tokens"]["EDS"])
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Send ZHC
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from zhlink import send_zhc
|
|
103
|
+
|
|
104
|
+
result = send_zhc(
|
|
105
|
+
private_key_wif="L...",
|
|
106
|
+
to_address="Z...",
|
|
107
|
+
amount="1.25",
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
print(result)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The sender address is derived from the private key automatically.
|
|
114
|
+
|
|
115
|
+
## Send USDZ Gas-Free
|
|
116
|
+
|
|
117
|
+
`send_usdz_gas_free` signs the USDZ transfer with the sender key and pays ZHC
|
|
118
|
+
gas from the admin gas wallet.
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from zhlink import send_usdz_gas_free
|
|
122
|
+
|
|
123
|
+
result = send_usdz_gas_free(
|
|
124
|
+
sender_private_key_wif="L...",
|
|
125
|
+
admin_private_key_wif="K...",
|
|
126
|
+
to_address="Z...",
|
|
127
|
+
amount="0.1",
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
print(result["broadcast"]["txid"])
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The function does the required checks automatically:
|
|
134
|
+
|
|
135
|
+
1. derives sender/admin addresses from WIF keys;
|
|
136
|
+
2. checks sender USDZ balance;
|
|
137
|
+
3. runs `callcontract` dry-run;
|
|
138
|
+
4. loads admin gas UTXO from ZeroScan;
|
|
139
|
+
5. skips locally used gas UTXO;
|
|
140
|
+
6. builds and signs rawtx locally;
|
|
141
|
+
7. runs `testmempoolaccept`;
|
|
142
|
+
8. if one UTXO is rejected, tries another UTXO;
|
|
143
|
+
9. broadcasts through ZeroScan;
|
|
144
|
+
10. falls back to RPC `sendrawtransaction`.
|
|
145
|
+
|
|
146
|
+
For mass sends, prepare independent admin gas UTXO first. One gas-free transfer
|
|
147
|
+
needs one spendable admin gas UTXO. The recommended ticket size is `0.5 ZHC`.
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from zhlink import admin_gas_wallet_info
|
|
151
|
+
|
|
152
|
+
info = admin_gas_wallet_info("K...")
|
|
153
|
+
print(info["suitable_gas_utxo_count"])
|
|
154
|
+
print(info["recommended_split_count"])
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Custom RPC / ZeroScan
|
|
158
|
+
|
|
159
|
+
Defaults:
|
|
160
|
+
|
|
161
|
+
- ZeroScan API: `https://ws.zeroscan.st`, `https://ws.zeroscan.io`
|
|
162
|
+
- RPC: `https://rpc.zeroscan.st`
|
|
163
|
+
- USDZ contract: `a48d0ee7365ce1add8e595de4d54344239f8ca28`
|
|
164
|
+
|
|
165
|
+
Override them when needed:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from zhlink import ZHLinkConfig, get_balance
|
|
169
|
+
|
|
170
|
+
config = ZHLinkConfig.public_network(
|
|
171
|
+
zeroscan_endpoints=("https://ws.zeroscan.st", "https://ws.zeroscan.io"),
|
|
172
|
+
public_rpc_urls=("https://rpc.zeroscan.st", "https://my-node.example/rpc"),
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
print(get_balance("Z...", config=config))
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Examples
|
|
179
|
+
|
|
180
|
+
Run examples one by one:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
cd /root/wallet/zhlink
|
|
184
|
+
PYTHONPATH=. python3 examples/create_wallet.py
|
|
185
|
+
PYTHONPATH=. python3 examples/create_bip39_wallet.py
|
|
186
|
+
PYTHONPATH=. ZHLINK_ADDRESS="Z..." python3 examples/check_balance.py
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Run all safe examples at once:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
cd /root/wallet/zhlink
|
|
193
|
+
PYTHONPATH=. python3 examples/run_all_examples.py
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Send examples are guarded by `RUN_REAL_SEND=1` and will not broadcast by
|
|
197
|
+
accident. Never commit real private keys.
|
|
198
|
+
|
|
199
|
+
## Publishing
|
|
200
|
+
|
|
201
|
+
GitHub Actions workflow `.github/workflows/python-publish.yml` builds, tests,
|
|
202
|
+
checks, and publishes the package to PyPI.
|
|
203
|
+
|
|
204
|
+
Release flow:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
git tag v0.1.0
|
|
208
|
+
git push origin v0.1.0
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The workflow uses PyPI Trusted Publishing, so the PyPI project must allow this
|
|
212
|
+
GitHub repository/workflow as a trusted publisher.
|
zhlink-0.1.0/README.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# ZHLink Python Library
|
|
2
|
+
|
|
3
|
+
`zhlink` is a self-contained Python library for ZHCASH.
|
|
4
|
+
|
|
5
|
+
The public API is intentionally small:
|
|
6
|
+
|
|
7
|
+
- create a new ZHC address;
|
|
8
|
+
- check ZHC + USDZ balance;
|
|
9
|
+
- send native ZHC from a private key;
|
|
10
|
+
- send USDZ with admin-paid ZHC gas;
|
|
11
|
+
- optionally read extra ZRC-20 token balances.
|
|
12
|
+
|
|
13
|
+
The raw transaction engine is bundled inside the package. Normal users only
|
|
14
|
+
import `zhlink`.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
Recommended Python:
|
|
19
|
+
|
|
20
|
+
- Python `3.10` or newer is required.
|
|
21
|
+
- Python `3.10` and `3.11` are the safest choices for deployment.
|
|
22
|
+
- Python `3.12` should work.
|
|
23
|
+
- Python `3.9` and older are not supported.
|
|
24
|
+
|
|
25
|
+
From PyPI:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install zhlink
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
From this folder:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cd /root/wallet/zhlink
|
|
35
|
+
python3 -m venv .venv
|
|
36
|
+
. .venv/bin/activate
|
|
37
|
+
pip install -e .
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For direct local use without install:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
cd /root/wallet/zhlink
|
|
44
|
+
export PYTHONPATH=/root/wallet/zhlink
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Create Address
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from zhlink import create_address
|
|
51
|
+
|
|
52
|
+
wallet = create_address()
|
|
53
|
+
|
|
54
|
+
print(wallet.address)
|
|
55
|
+
print(wallet.priv_key)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Private keys are generated locally. The library never sends private keys to
|
|
59
|
+
ZeroScan or RPC.
|
|
60
|
+
|
|
61
|
+
## Get Balance
|
|
62
|
+
|
|
63
|
+
By default `get_balance` returns ZHC and USDZ.
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from zhlink import get_balance
|
|
67
|
+
|
|
68
|
+
balance = get_balance("Z...")
|
|
69
|
+
|
|
70
|
+
print(balance["zhc"])
|
|
71
|
+
print(balance["usdz"])
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Extra ZRC-20 tokens can be requested when needed:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from zhlink import get_balance
|
|
78
|
+
|
|
79
|
+
balance = get_balance(
|
|
80
|
+
"Z...",
|
|
81
|
+
tokens={"EDS": "dc71958156a945d3071374521e1a7a42f5ba8038"},
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
print(balance["tokens"]["EDS"])
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Send ZHC
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from zhlink import send_zhc
|
|
91
|
+
|
|
92
|
+
result = send_zhc(
|
|
93
|
+
private_key_wif="L...",
|
|
94
|
+
to_address="Z...",
|
|
95
|
+
amount="1.25",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
print(result)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The sender address is derived from the private key automatically.
|
|
102
|
+
|
|
103
|
+
## Send USDZ Gas-Free
|
|
104
|
+
|
|
105
|
+
`send_usdz_gas_free` signs the USDZ transfer with the sender key and pays ZHC
|
|
106
|
+
gas from the admin gas wallet.
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from zhlink import send_usdz_gas_free
|
|
110
|
+
|
|
111
|
+
result = send_usdz_gas_free(
|
|
112
|
+
sender_private_key_wif="L...",
|
|
113
|
+
admin_private_key_wif="K...",
|
|
114
|
+
to_address="Z...",
|
|
115
|
+
amount="0.1",
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
print(result["broadcast"]["txid"])
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The function does the required checks automatically:
|
|
122
|
+
|
|
123
|
+
1. derives sender/admin addresses from WIF keys;
|
|
124
|
+
2. checks sender USDZ balance;
|
|
125
|
+
3. runs `callcontract` dry-run;
|
|
126
|
+
4. loads admin gas UTXO from ZeroScan;
|
|
127
|
+
5. skips locally used gas UTXO;
|
|
128
|
+
6. builds and signs rawtx locally;
|
|
129
|
+
7. runs `testmempoolaccept`;
|
|
130
|
+
8. if one UTXO is rejected, tries another UTXO;
|
|
131
|
+
9. broadcasts through ZeroScan;
|
|
132
|
+
10. falls back to RPC `sendrawtransaction`.
|
|
133
|
+
|
|
134
|
+
For mass sends, prepare independent admin gas UTXO first. One gas-free transfer
|
|
135
|
+
needs one spendable admin gas UTXO. The recommended ticket size is `0.5 ZHC`.
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from zhlink import admin_gas_wallet_info
|
|
139
|
+
|
|
140
|
+
info = admin_gas_wallet_info("K...")
|
|
141
|
+
print(info["suitable_gas_utxo_count"])
|
|
142
|
+
print(info["recommended_split_count"])
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Custom RPC / ZeroScan
|
|
146
|
+
|
|
147
|
+
Defaults:
|
|
148
|
+
|
|
149
|
+
- ZeroScan API: `https://ws.zeroscan.st`, `https://ws.zeroscan.io`
|
|
150
|
+
- RPC: `https://rpc.zeroscan.st`
|
|
151
|
+
- USDZ contract: `a48d0ee7365ce1add8e595de4d54344239f8ca28`
|
|
152
|
+
|
|
153
|
+
Override them when needed:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from zhlink import ZHLinkConfig, get_balance
|
|
157
|
+
|
|
158
|
+
config = ZHLinkConfig.public_network(
|
|
159
|
+
zeroscan_endpoints=("https://ws.zeroscan.st", "https://ws.zeroscan.io"),
|
|
160
|
+
public_rpc_urls=("https://rpc.zeroscan.st", "https://my-node.example/rpc"),
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
print(get_balance("Z...", config=config))
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Examples
|
|
167
|
+
|
|
168
|
+
Run examples one by one:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
cd /root/wallet/zhlink
|
|
172
|
+
PYTHONPATH=. python3 examples/create_wallet.py
|
|
173
|
+
PYTHONPATH=. python3 examples/create_bip39_wallet.py
|
|
174
|
+
PYTHONPATH=. ZHLINK_ADDRESS="Z..." python3 examples/check_balance.py
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Run all safe examples at once:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
cd /root/wallet/zhlink
|
|
181
|
+
PYTHONPATH=. python3 examples/run_all_examples.py
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Send examples are guarded by `RUN_REAL_SEND=1` and will not broadcast by
|
|
185
|
+
accident. Never commit real private keys.
|
|
186
|
+
|
|
187
|
+
## Publishing
|
|
188
|
+
|
|
189
|
+
GitHub Actions workflow `.github/workflows/python-publish.yml` builds, tests,
|
|
190
|
+
checks, and publishes the package to PyPI.
|
|
191
|
+
|
|
192
|
+
Release flow:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
git tag v0.1.0
|
|
196
|
+
git push origin v0.1.0
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The workflow uses PyPI Trusted Publishing, so the PyPI project must allow this
|
|
200
|
+
GitHub repository/workflow as a trusted publisher.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "zhlink"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Self-contained Python library for ZHCASH addresses, balances, ZHC sends, and USDZ gas-free sends."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"cryptography>=42",
|
|
13
|
+
"httpx==0.28.1",
|
|
14
|
+
"mnemonic==0.21",
|
|
15
|
+
"pycryptodome>=3.20",
|
|
16
|
+
]
|
|
17
|
+
authors = [
|
|
18
|
+
{ name = "ZHCASH" },
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[tool.setuptools]
|
|
22
|
+
include-package-data = true
|
|
23
|
+
|
|
24
|
+
[tool.setuptools.packages.find]
|
|
25
|
+
where = ["."]
|
|
26
|
+
include = ["zhlink*"]
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.package-data]
|
|
29
|
+
zhlink = [
|
|
30
|
+
"_vendor/bip39_english.txt",
|
|
31
|
+
"_vendor/zhc_rawtx/*.py",
|
|
32
|
+
]
|
zhlink-0.1.0/setup.cfg
ADDED