btc-toolkit 1.0.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.
- btc_toolkit-1.0.0/LICENSE +21 -0
- btc_toolkit-1.0.0/PKG-INFO +256 -0
- btc_toolkit-1.0.0/README.md +229 -0
- btc_toolkit-1.0.0/btc_toolkit/__init__.py +3 -0
- btc_toolkit-1.0.0/btc_toolkit/__main__.py +6 -0
- btc_toolkit-1.0.0/btc_toolkit/api.py +94 -0
- btc_toolkit-1.0.0/btc_toolkit/balance.py +132 -0
- btc_toolkit-1.0.0/btc_toolkit/block.py +139 -0
- btc_toolkit-1.0.0/btc_toolkit/cli.py +469 -0
- btc_toolkit-1.0.0/btc_toolkit/colors.py +40 -0
- btc_toolkit-1.0.0/btc_toolkit/fees.py +90 -0
- btc_toolkit-1.0.0/btc_toolkit/opreturn.py +187 -0
- btc_toolkit-1.0.0/btc_toolkit/utxo.py +126 -0
- btc_toolkit-1.0.0/btc_toolkit.egg-info/PKG-INFO +256 -0
- btc_toolkit-1.0.0/btc_toolkit.egg-info/SOURCES.txt +23 -0
- btc_toolkit-1.0.0/btc_toolkit.egg-info/dependency_links.txt +1 -0
- btc_toolkit-1.0.0/btc_toolkit.egg-info/entry_points.txt +2 -0
- btc_toolkit-1.0.0/btc_toolkit.egg-info/top_level.txt +1 -0
- btc_toolkit-1.0.0/pyproject.toml +43 -0
- btc_toolkit-1.0.0/setup.cfg +4 -0
- btc_toolkit-1.0.0/tests/test_balance.py +161 -0
- btc_toolkit-1.0.0/tests/test_block.py +113 -0
- btc_toolkit-1.0.0/tests/test_fees.py +100 -0
- btc_toolkit-1.0.0/tests/test_opreturn.py +122 -0
- btc_toolkit-1.0.0/tests/test_utxo.py +94 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Davi de Jesus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: btc-toolkit
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Bitcoin CLI toolkit — OP_RETURN decoder, balance checker, fee estimator & more. Zero deps, no Bitcoin Core required.
|
|
5
|
+
Author-email: Davi de Jesus <devdavidejesus@users.noreply.github.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/devdavidejesus/btc-toolkit
|
|
8
|
+
Project-URL: Repository, https://github.com/devdavidejesus/btc-toolkit
|
|
9
|
+
Project-URL: Issues, https://github.com/devdavidejesus/btc-toolkit/issues
|
|
10
|
+
Keywords: bitcoin,op_return,balance,mempool,cli,blockchain
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
<div align="center">
|
|
29
|
+
|
|
30
|
+
# ₿ btc-toolkit
|
|
31
|
+
|
|
32
|
+
**Bitcoin CLI toolkit — zero dependencies, no Bitcoin Core required.**
|
|
33
|
+
|
|
34
|
+
Query the Bitcoin network directly via the [Mempool.space](https://mempool.space) public API.
|
|
35
|
+
|
|
36
|
+
[](https://github.com/devdavidejesus/btc-toolkit/actions/workflows/tests.yml)
|
|
37
|
+
[](https://github.com/devdavidejesus/btc-toolkit/tags)
|
|
38
|
+
[](https://github.com/devdavidejesus/btc-toolkit/blob/main/pyproject.toml)
|
|
39
|
+
[](https://github.com/devdavidejesus/btc-toolkit/blob/main/pyproject.toml)
|
|
40
|
+
[](LICENSE)
|
|
41
|
+
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Commands
|
|
47
|
+
|
|
48
|
+
| Command | Description | Status |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `btc-toolkit opreturn <txid>` | Decode OP_RETURN messages from a transaction | ✅ Phase 1 |
|
|
51
|
+
| `btc-toolkit balance <address>` | Confirmed + unconfirmed balance of any address | ✅ Phase 2 |
|
|
52
|
+
| `btc-toolkit fees` | Recommended fee rates + mempool backlog | ✅ Phase 3 |
|
|
53
|
+
| `btc-toolkit block <height\|hash>` | Block metadata by height, hash, or latest | ✅ Phase 4 |
|
|
54
|
+
| `btc-toolkit utxo <address>` | Unspent outputs of any address | ✅ Phase 5 |
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
**Requirements:** Python 3.10+
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/devdavidejesus/btc-toolkit.git
|
|
62
|
+
cd btc-toolkit
|
|
63
|
+
pip install -e .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Usage
|
|
67
|
+
|
|
68
|
+
### balance — check any address
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
btc-toolkit balance 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Shows confirmed balance, unconfirmed (mempool) balance, and total — in BTC and satoshis. Supports all address types: Legacy (P2PKH), P2SH, SegWit (Bech32), and Taproot.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# JSON output for scripting
|
|
78
|
+
btc-toolkit balance <address> --json
|
|
79
|
+
|
|
80
|
+
# Testnet
|
|
81
|
+
btc-toolkit balance <address> --network testnet
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
BTC conversion uses integer arithmetic (no floats) — satoshi-exact, always.
|
|
85
|
+
|
|
86
|
+
### fees — current rates and mempool backlog
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
btc-toolkit fees
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Shows the five recommended fee tiers (sat/vB) — fastest, half hour, hour, economy, minimum — plus mempool backlog: pending tx count, size in vMB, and a rough estimate of blocks needed to clear it.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# JSON output for scripting
|
|
96
|
+
btc-toolkit fees --json
|
|
97
|
+
|
|
98
|
+
# Testnet
|
|
99
|
+
btc-toolkit fees --network testnet
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### block — inspect any block
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
btc-toolkit block latest # chain tip
|
|
106
|
+
btc-toolkit block 0 # by height (genesis)
|
|
107
|
+
btc-toolkit block 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f # by hash
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Shows height, hash, mined timestamp (UTC), tx count, size, weight, difficulty, nonce, and previous block hash.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# JSON output for scripting
|
|
114
|
+
btc-toolkit block latest --json
|
|
115
|
+
|
|
116
|
+
# Testnet
|
|
117
|
+
btc-toolkit block latest --network testnet
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### utxo — unspent outputs of any address
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
btc-toolkit utxo bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Lists every UTXO sorted by value (largest first), with txid:vout, value in BTC and sats, confirmation status, and block height. Shows aggregate count and total value.
|
|
127
|
+
|
|
128
|
+
> **Known limitation:** addresses with tens of thousands of UTXOs (e.g. Satoshi's genesis address, ~76k donation outputs) exceed the upstream electrs response limit and return HTTP 400. Use `balance` for aggregate stats on such addresses — discovered and verified in production.
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Only confirmed UTXOs
|
|
132
|
+
btc-toolkit utxo <address> --confirmed-only
|
|
133
|
+
|
|
134
|
+
# Show more than 15 entries
|
|
135
|
+
btc-toolkit utxo <address> --limit 50
|
|
136
|
+
|
|
137
|
+
# JSON output (always includes all UTXOs)
|
|
138
|
+
btc-toolkit utxo <address> --json
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### opreturn — decode embedded messages
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
btc-toolkit opreturn f4ac7abcb689df30ec5e8d829733622f389ca91367c47b319bc582e653cd8cab
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+

|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# JSON output
|
|
151
|
+
btc-toolkit opreturn <txid> --json
|
|
152
|
+
|
|
153
|
+
# Raw hex only
|
|
154
|
+
btc-toolkit opreturn <txid> --raw
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Transactions to Try
|
|
158
|
+
|
|
159
|
+
Real, verified OP_RETURN transactions on mainnet. Verify each one yourself on [mempool.space](https://mempool.space).
|
|
160
|
+
|
|
161
|
+
| TXID | Description |
|
|
162
|
+
|---|---|
|
|
163
|
+
| `f4ac7abcb689df30ec5e8d829733622f389ca91367c47b319bc582e653cd8cab` | "Craig Wright is a liar and a fraud" — 34 bytes ([verify on-chain](https://mempool.space/tx/f4ac7abcb689df30ec5e8d829733622f389ca91367c47b319bc582e653cd8cab)) |
|
|
164
|
+
| `2033435de7ce307341231e818ed937cd3a5e8597381fd83a7e5b0234f61b38d3` | "learnmeabitcoin" — 75-byte OP_RETURN with null-padded ASCII ([verify on-chain](https://mempool.space/tx/2033435de7ce307341231e818ed937cd3a5e8597381fd83a7e5b0234f61b38d3)) |
|
|
165
|
+
|
|
166
|
+
> **Note:** Satoshi's famous "Chancellor on brink of second bailout for banks" message is in the
|
|
167
|
+
> **coinbase scriptSig** of the genesis block — NOT in an OP_RETURN output. That's a common
|
|
168
|
+
> misconception. This tool reads OP_RETURN outputs only, which is the standard mechanism
|
|
169
|
+
> for embedding data in Bitcoin transactions (introduced as standard in Bitcoin Core v0.9.0, March 2014).
|
|
170
|
+
|
|
171
|
+
## Architecture
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
btc-toolkit/
|
|
175
|
+
├── btc_toolkit/
|
|
176
|
+
│ ├── __init__.py # Package version
|
|
177
|
+
│ ├── __main__.py # python -m entry point
|
|
178
|
+
│ ├── cli.py # Unified CLI with subcommands
|
|
179
|
+
│ ├── api.py # Shared Mempool.space HTTP client
|
|
180
|
+
│ ├── colors.py # Shared terminal color helpers
|
|
181
|
+
│ ├── opreturn.py # Phase 1 — OP_RETURN decoder
|
|
182
|
+
│ ├── balance.py # Phase 2 — Address balance checker
|
|
183
|
+
│ ├── fees.py # Phase 3 — Fee estimator
|
|
184
|
+
│ ├── block.py # Phase 4 — Block info explorer
|
|
185
|
+
│ └── utxo.py # Phase 5 — UTXO set inspector
|
|
186
|
+
├── tests/
|
|
187
|
+
│ ├── test_opreturn.py # 18 tests (mocked API + parser validation)
|
|
188
|
+
│ ├── test_balance.py # 18 tests (sats math + API response parsing)
|
|
189
|
+
│ ├── test_fees.py # 6 tests (rates + backlog parsing)
|
|
190
|
+
│ ├── test_block.py # 12 tests (ref detection + genesis data)
|
|
191
|
+
│ └── test_utxo.py # 8 tests (aggregates + filters)
|
|
192
|
+
├── pyproject.toml
|
|
193
|
+
├── LICENSE # MIT
|
|
194
|
+
└── README.md
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Every subcommand shares one HTTP client (`api.py`) — new phases add a module + a subcommand, nothing else.
|
|
198
|
+
|
|
199
|
+
Zero external dependencies — Python standard library only (`urllib`, `json`, `argparse`).
|
|
200
|
+
|
|
201
|
+
## Testing
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
python -m pytest tests/ -v
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
62 tests, all API calls mocked — the suite runs offline.
|
|
208
|
+
|
|
209
|
+

|
|
210
|
+
|
|
211
|
+
## How balance is computed
|
|
212
|
+
|
|
213
|
+
The Mempool.space `/address` endpoint returns `chain_stats` (confirmed) and `mempool_stats` (unconfirmed), each with `funded_txo_sum` and `spent_txo_sum` in satoshis.
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
confirmed = chain_stats.funded_txo_sum - chain_stats.spent_txo_sum
|
|
217
|
+
unconfirmed = mempool_stats.funded_txo_sum - mempool_stats.spent_txo_sum
|
|
218
|
+
total = confirmed + unconfirmed
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
This is the same model used by Esplora/Electrs. Don't trust this README — verify against `https://mempool.space/api/address/<address>` yourself.
|
|
222
|
+
|
|
223
|
+
## Roadmap
|
|
224
|
+
|
|
225
|
+
- [x] **Phase 1** — OP_RETURN Reader
|
|
226
|
+
- [x] **Phase 2** — Address Balance Checker
|
|
227
|
+
- [x] **Phase 3** — Fee Estimator (mempool-based)
|
|
228
|
+
- [x] **Phase 4** — Block Info Explorer
|
|
229
|
+
- [x] **Phase 5** — UTXO Set Inspector
|
|
230
|
+
|
|
231
|
+
All five phases complete — one philosophy throughout: **zero dependencies, no Bitcoin Core, verify everything on-chain.**
|
|
232
|
+
|
|
233
|
+
## Don't Trust, Verify
|
|
234
|
+
|
|
235
|
+
Every txid, address, hex value, and technical claim in this README can be independently verified:
|
|
236
|
+
- Transaction data: `https://mempool.space/api/tx/<txid>`
|
|
237
|
+
- Address data: `https://mempool.space/api/address/<address>`
|
|
238
|
+
- Fee data: `https://mempool.space/api/v1/fees/recommended`
|
|
239
|
+
- Block data: `https://mempool.space/api/block/<hash>`
|
|
240
|
+
- UTXO data: `https://mempool.space/api/address/<address>/utxo`
|
|
241
|
+
- OP_RETURN spec: [learnmeabitcoin.com/technical/script/return](https://learnmeabitcoin.com/technical/script/return/)
|
|
242
|
+
- Esplora API model: [github.com/Blockstream/esplora/blob/master/API.md](https://github.com/Blockstream/esplora/blob/master/API.md)
|
|
243
|
+
|
|
244
|
+
## Contributing
|
|
245
|
+
|
|
246
|
+
Found a bug or want to help with a phase from the roadmap? Open an [issue](https://github.com/devdavidejesus/btc-toolkit/issues) or a PR. Every contribution must keep the core rules: stdlib only, tests mocked, claims verifiable on-chain.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
<div align="center">
|
|
251
|
+
|
|
252
|
+
Licensed under [MIT](LICENSE) · Built by [@devdavidejesus](https://github.com/devdavidejesus)
|
|
253
|
+
|
|
254
|
+
*"Don't Trust, Verify."*
|
|
255
|
+
|
|
256
|
+
</div>
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# ₿ btc-toolkit
|
|
4
|
+
|
|
5
|
+
**Bitcoin CLI toolkit — zero dependencies, no Bitcoin Core required.**
|
|
6
|
+
|
|
7
|
+
Query the Bitcoin network directly via the [Mempool.space](https://mempool.space) public API.
|
|
8
|
+
|
|
9
|
+
[](https://github.com/devdavidejesus/btc-toolkit/actions/workflows/tests.yml)
|
|
10
|
+
[](https://github.com/devdavidejesus/btc-toolkit/tags)
|
|
11
|
+
[](https://github.com/devdavidejesus/btc-toolkit/blob/main/pyproject.toml)
|
|
12
|
+
[](https://github.com/devdavidejesus/btc-toolkit/blob/main/pyproject.toml)
|
|
13
|
+
[](LICENSE)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Commands
|
|
20
|
+
|
|
21
|
+
| Command | Description | Status |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `btc-toolkit opreturn <txid>` | Decode OP_RETURN messages from a transaction | ✅ Phase 1 |
|
|
24
|
+
| `btc-toolkit balance <address>` | Confirmed + unconfirmed balance of any address | ✅ Phase 2 |
|
|
25
|
+
| `btc-toolkit fees` | Recommended fee rates + mempool backlog | ✅ Phase 3 |
|
|
26
|
+
| `btc-toolkit block <height\|hash>` | Block metadata by height, hash, or latest | ✅ Phase 4 |
|
|
27
|
+
| `btc-toolkit utxo <address>` | Unspent outputs of any address | ✅ Phase 5 |
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
**Requirements:** Python 3.10+
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
git clone https://github.com/devdavidejesus/btc-toolkit.git
|
|
35
|
+
cd btc-toolkit
|
|
36
|
+
pip install -e .
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
### balance — check any address
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
btc-toolkit balance 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Shows confirmed balance, unconfirmed (mempool) balance, and total — in BTC and satoshis. Supports all address types: Legacy (P2PKH), P2SH, SegWit (Bech32), and Taproot.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# JSON output for scripting
|
|
51
|
+
btc-toolkit balance <address> --json
|
|
52
|
+
|
|
53
|
+
# Testnet
|
|
54
|
+
btc-toolkit balance <address> --network testnet
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
BTC conversion uses integer arithmetic (no floats) — satoshi-exact, always.
|
|
58
|
+
|
|
59
|
+
### fees — current rates and mempool backlog
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
btc-toolkit fees
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Shows the five recommended fee tiers (sat/vB) — fastest, half hour, hour, economy, minimum — plus mempool backlog: pending tx count, size in vMB, and a rough estimate of blocks needed to clear it.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# JSON output for scripting
|
|
69
|
+
btc-toolkit fees --json
|
|
70
|
+
|
|
71
|
+
# Testnet
|
|
72
|
+
btc-toolkit fees --network testnet
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### block — inspect any block
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
btc-toolkit block latest # chain tip
|
|
79
|
+
btc-toolkit block 0 # by height (genesis)
|
|
80
|
+
btc-toolkit block 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f # by hash
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Shows height, hash, mined timestamp (UTC), tx count, size, weight, difficulty, nonce, and previous block hash.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# JSON output for scripting
|
|
87
|
+
btc-toolkit block latest --json
|
|
88
|
+
|
|
89
|
+
# Testnet
|
|
90
|
+
btc-toolkit block latest --network testnet
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### utxo — unspent outputs of any address
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
btc-toolkit utxo bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Lists every UTXO sorted by value (largest first), with txid:vout, value in BTC and sats, confirmation status, and block height. Shows aggregate count and total value.
|
|
100
|
+
|
|
101
|
+
> **Known limitation:** addresses with tens of thousands of UTXOs (e.g. Satoshi's genesis address, ~76k donation outputs) exceed the upstream electrs response limit and return HTTP 400. Use `balance` for aggregate stats on such addresses — discovered and verified in production.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Only confirmed UTXOs
|
|
105
|
+
btc-toolkit utxo <address> --confirmed-only
|
|
106
|
+
|
|
107
|
+
# Show more than 15 entries
|
|
108
|
+
btc-toolkit utxo <address> --limit 50
|
|
109
|
+
|
|
110
|
+
# JSON output (always includes all UTXOs)
|
|
111
|
+
btc-toolkit utxo <address> --json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### opreturn — decode embedded messages
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
btc-toolkit opreturn f4ac7abcb689df30ec5e8d829733622f389ca91367c47b319bc582e653cd8cab
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+

|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# JSON output
|
|
124
|
+
btc-toolkit opreturn <txid> --json
|
|
125
|
+
|
|
126
|
+
# Raw hex only
|
|
127
|
+
btc-toolkit opreturn <txid> --raw
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Transactions to Try
|
|
131
|
+
|
|
132
|
+
Real, verified OP_RETURN transactions on mainnet. Verify each one yourself on [mempool.space](https://mempool.space).
|
|
133
|
+
|
|
134
|
+
| TXID | Description |
|
|
135
|
+
|---|---|
|
|
136
|
+
| `f4ac7abcb689df30ec5e8d829733622f389ca91367c47b319bc582e653cd8cab` | "Craig Wright is a liar and a fraud" — 34 bytes ([verify on-chain](https://mempool.space/tx/f4ac7abcb689df30ec5e8d829733622f389ca91367c47b319bc582e653cd8cab)) |
|
|
137
|
+
| `2033435de7ce307341231e818ed937cd3a5e8597381fd83a7e5b0234f61b38d3` | "learnmeabitcoin" — 75-byte OP_RETURN with null-padded ASCII ([verify on-chain](https://mempool.space/tx/2033435de7ce307341231e818ed937cd3a5e8597381fd83a7e5b0234f61b38d3)) |
|
|
138
|
+
|
|
139
|
+
> **Note:** Satoshi's famous "Chancellor on brink of second bailout for banks" message is in the
|
|
140
|
+
> **coinbase scriptSig** of the genesis block — NOT in an OP_RETURN output. That's a common
|
|
141
|
+
> misconception. This tool reads OP_RETURN outputs only, which is the standard mechanism
|
|
142
|
+
> for embedding data in Bitcoin transactions (introduced as standard in Bitcoin Core v0.9.0, March 2014).
|
|
143
|
+
|
|
144
|
+
## Architecture
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
btc-toolkit/
|
|
148
|
+
├── btc_toolkit/
|
|
149
|
+
│ ├── __init__.py # Package version
|
|
150
|
+
│ ├── __main__.py # python -m entry point
|
|
151
|
+
│ ├── cli.py # Unified CLI with subcommands
|
|
152
|
+
│ ├── api.py # Shared Mempool.space HTTP client
|
|
153
|
+
│ ├── colors.py # Shared terminal color helpers
|
|
154
|
+
│ ├── opreturn.py # Phase 1 — OP_RETURN decoder
|
|
155
|
+
│ ├── balance.py # Phase 2 — Address balance checker
|
|
156
|
+
│ ├── fees.py # Phase 3 — Fee estimator
|
|
157
|
+
│ ├── block.py # Phase 4 — Block info explorer
|
|
158
|
+
│ └── utxo.py # Phase 5 — UTXO set inspector
|
|
159
|
+
├── tests/
|
|
160
|
+
│ ├── test_opreturn.py # 18 tests (mocked API + parser validation)
|
|
161
|
+
│ ├── test_balance.py # 18 tests (sats math + API response parsing)
|
|
162
|
+
│ ├── test_fees.py # 6 tests (rates + backlog parsing)
|
|
163
|
+
│ ├── test_block.py # 12 tests (ref detection + genesis data)
|
|
164
|
+
│ └── test_utxo.py # 8 tests (aggregates + filters)
|
|
165
|
+
├── pyproject.toml
|
|
166
|
+
├── LICENSE # MIT
|
|
167
|
+
└── README.md
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Every subcommand shares one HTTP client (`api.py`) — new phases add a module + a subcommand, nothing else.
|
|
171
|
+
|
|
172
|
+
Zero external dependencies — Python standard library only (`urllib`, `json`, `argparse`).
|
|
173
|
+
|
|
174
|
+
## Testing
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
python -m pytest tests/ -v
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
62 tests, all API calls mocked — the suite runs offline.
|
|
181
|
+
|
|
182
|
+

|
|
183
|
+
|
|
184
|
+
## How balance is computed
|
|
185
|
+
|
|
186
|
+
The Mempool.space `/address` endpoint returns `chain_stats` (confirmed) and `mempool_stats` (unconfirmed), each with `funded_txo_sum` and `spent_txo_sum` in satoshis.
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
confirmed = chain_stats.funded_txo_sum - chain_stats.spent_txo_sum
|
|
190
|
+
unconfirmed = mempool_stats.funded_txo_sum - mempool_stats.spent_txo_sum
|
|
191
|
+
total = confirmed + unconfirmed
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
This is the same model used by Esplora/Electrs. Don't trust this README — verify against `https://mempool.space/api/address/<address>` yourself.
|
|
195
|
+
|
|
196
|
+
## Roadmap
|
|
197
|
+
|
|
198
|
+
- [x] **Phase 1** — OP_RETURN Reader
|
|
199
|
+
- [x] **Phase 2** — Address Balance Checker
|
|
200
|
+
- [x] **Phase 3** — Fee Estimator (mempool-based)
|
|
201
|
+
- [x] **Phase 4** — Block Info Explorer
|
|
202
|
+
- [x] **Phase 5** — UTXO Set Inspector
|
|
203
|
+
|
|
204
|
+
All five phases complete — one philosophy throughout: **zero dependencies, no Bitcoin Core, verify everything on-chain.**
|
|
205
|
+
|
|
206
|
+
## Don't Trust, Verify
|
|
207
|
+
|
|
208
|
+
Every txid, address, hex value, and technical claim in this README can be independently verified:
|
|
209
|
+
- Transaction data: `https://mempool.space/api/tx/<txid>`
|
|
210
|
+
- Address data: `https://mempool.space/api/address/<address>`
|
|
211
|
+
- Fee data: `https://mempool.space/api/v1/fees/recommended`
|
|
212
|
+
- Block data: `https://mempool.space/api/block/<hash>`
|
|
213
|
+
- UTXO data: `https://mempool.space/api/address/<address>/utxo`
|
|
214
|
+
- OP_RETURN spec: [learnmeabitcoin.com/technical/script/return](https://learnmeabitcoin.com/technical/script/return/)
|
|
215
|
+
- Esplora API model: [github.com/Blockstream/esplora/blob/master/API.md](https://github.com/Blockstream/esplora/blob/master/API.md)
|
|
216
|
+
|
|
217
|
+
## Contributing
|
|
218
|
+
|
|
219
|
+
Found a bug or want to help with a phase from the roadmap? Open an [issue](https://github.com/devdavidejesus/btc-toolkit/issues) or a PR. Every contribution must keep the core rules: stdlib only, tests mocked, claims verifiable on-chain.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
<div align="center">
|
|
224
|
+
|
|
225
|
+
Licensed under [MIT](LICENSE) · Built by [@devdavidejesus](https://github.com/devdavidejesus)
|
|
226
|
+
|
|
227
|
+
*"Don't Trust, Verify."*
|
|
228
|
+
|
|
229
|
+
</div>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared Mempool.space API client.
|
|
3
|
+
|
|
4
|
+
Centralizes all HTTP communication with the Mempool.space REST API.
|
|
5
|
+
Every subcommand (opreturn, balance, fees, block, utxo) uses this module
|
|
6
|
+
instead of duplicating connection logic.
|
|
7
|
+
|
|
8
|
+
No external dependencies — standard library only.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import urllib.request
|
|
13
|
+
import urllib.error
|
|
14
|
+
|
|
15
|
+
from . import __version__
|
|
16
|
+
|
|
17
|
+
# Mempool.space API base URLs
|
|
18
|
+
MEMPOOL_API = "https://mempool.space/api"
|
|
19
|
+
MEMPOOL_TESTNET_API = "https://mempool.space/testnet/api"
|
|
20
|
+
|
|
21
|
+
SUPPORTED_NETWORKS = ("mainnet", "testnet")
|
|
22
|
+
|
|
23
|
+
_USER_AGENT = f"btc-toolkit/{__version__}"
|
|
24
|
+
_TIMEOUT = 15
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MempoolAPIError(Exception):
|
|
28
|
+
"""Raised when the Mempool.space API returns an error."""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class NotFoundError(MempoolAPIError):
|
|
32
|
+
"""Raised when a requested resource (tx, address, block) is not found."""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_api_base(network: str) -> str:
|
|
36
|
+
"""Return the correct API base URL for the given network."""
|
|
37
|
+
if network not in SUPPORTED_NETWORKS:
|
|
38
|
+
raise ValueError(
|
|
39
|
+
f"Unsupported network: {network}. Use one of: {SUPPORTED_NETWORKS}"
|
|
40
|
+
)
|
|
41
|
+
if network == "testnet":
|
|
42
|
+
return MEMPOOL_TESTNET_API
|
|
43
|
+
return MEMPOOL_API
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_json(path: str, network: str = "mainnet") -> dict | list:
|
|
47
|
+
"""
|
|
48
|
+
GET a Mempool.space API endpoint and return parsed JSON.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
path: API path beginning with '/', e.g. '/tx/<txid>' or '/address/<addr>'.
|
|
52
|
+
network: 'mainnet' or 'testnet'.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Parsed JSON (dict or list).
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
NotFoundError: On HTTP 404.
|
|
59
|
+
MempoolAPIError: On other HTTP or connection errors.
|
|
60
|
+
"""
|
|
61
|
+
api_base = get_api_base(network)
|
|
62
|
+
url = f"{api_base}{path}"
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
req = urllib.request.Request(url, headers={"User-Agent": _USER_AGENT})
|
|
66
|
+
with urllib.request.urlopen(req, timeout=_TIMEOUT) as resp:
|
|
67
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
68
|
+
except urllib.error.HTTPError as e:
|
|
69
|
+
if e.code == 404:
|
|
70
|
+
raise NotFoundError(f"Not found: {path}") from e
|
|
71
|
+
raise MempoolAPIError(f"API error {e.code}: {e.reason}") from e
|
|
72
|
+
except urllib.error.URLError as e:
|
|
73
|
+
raise MempoolAPIError(f"Connection error: {e.reason}") from e
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_text(path: str, network: str = "mainnet") -> str:
|
|
77
|
+
"""
|
|
78
|
+
GET a Mempool.space API endpoint that returns plain text (not JSON).
|
|
79
|
+
|
|
80
|
+
Used for endpoints like /blocks/tip/height that return a bare number.
|
|
81
|
+
"""
|
|
82
|
+
api_base = get_api_base(network)
|
|
83
|
+
url = f"{api_base}{path}"
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
req = urllib.request.Request(url, headers={"User-Agent": _USER_AGENT})
|
|
87
|
+
with urllib.request.urlopen(req, timeout=_TIMEOUT) as resp:
|
|
88
|
+
return resp.read().decode("utf-8").strip()
|
|
89
|
+
except urllib.error.HTTPError as e:
|
|
90
|
+
if e.code == 404:
|
|
91
|
+
raise NotFoundError(f"Not found: {path}") from e
|
|
92
|
+
raise MempoolAPIError(f"API error {e.code}: {e.reason}") from e
|
|
93
|
+
except urllib.error.URLError as e:
|
|
94
|
+
raise MempoolAPIError(f"Connection error: {e.reason}") from e
|