defistream 1.2.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.
@@ -0,0 +1,23 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(git log:*)",
5
+ "Bash(python -m pytest:*)",
6
+ "Bash(python3 -m pytest:*)",
7
+ "Bash(git add:*)",
8
+ "Bash(git commit -m \"$\\(cat <<''EOF''\nAdd label/category filters and multi-value support to query builders\n\nAdd involving, involving_label, involving_category, sender_label,\nsender_category, receiver_label, receiver_category methods to both\nQueryBuilder and AsyncQueryBuilder. Update sender/receiver/from_address/\nto_address to accept varargs for multi-value filtering. Add SQL safety\nvalidation for label/category params and mutual exclusivity enforcement\nbetween involving* and sender*/receiver* filter slots.\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
9
+ "Bash(python3 -m build:*)",
10
+ "Bash(python3:*)",
11
+ "Bash(pip3 install:*)",
12
+ "Bash(/home/mvp/Running/Horatio_Chain_Scan/DeFiStream/python-client/.venv/bin/pip install:*)",
13
+ "Bash(/home/mvp/Running/Horatio_Chain_Scan/DeFiStream/python-client/.venv/bin/python:*)",
14
+ "Bash(source:*)",
15
+ "Bash(TWINE_USERNAME=__token__ TWINE_PASSWORD=\"$PYPI_PASSWORD\" /home/mvp/Running/Horatio_Chain_Scan/DeFiStream/python-client/.venv/bin/python:*)",
16
+ "Bash(git commit -m \"$\\(cat <<''EOF''\nBump python-client version to 1.1.0\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
17
+ "Bash(git push:*)",
18
+ "Bash(git subtree push:*)",
19
+ "Bash(.venv/bin/python -m pytest:*)",
20
+ "Bash(.venv/bin/python:*)"
21
+ ]
22
+ }
23
+ }
@@ -0,0 +1,51 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ .Python
8
+ build/
9
+ develop-eggs/
10
+ dist/
11
+ downloads/
12
+ eggs/
13
+ .eggs/
14
+ lib/
15
+ lib64/
16
+ parts/
17
+ sdist/
18
+ var/
19
+ wheels/
20
+ *.egg-info/
21
+ .installed.cfg
22
+ *.egg
23
+
24
+ # Virtual environments
25
+ venv/
26
+ ENV/
27
+ env/
28
+ .venv/
29
+
30
+ # IDE
31
+ .idea/
32
+ .vscode/
33
+ *.swp
34
+ *.swo
35
+
36
+ # Testing
37
+ .pytest_cache/
38
+ .coverage
39
+ htmlcov/
40
+ .tox/
41
+ .nox/
42
+
43
+ # Type checking
44
+ .mypy_cache/
45
+
46
+ # Jupyter
47
+ .ipynb_checkpoints/
48
+
49
+ # Environment
50
+ .env
51
+ .env.local
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DeFiStream
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,522 @@
1
+ Metadata-Version: 2.4
2
+ Name: defistream
3
+ Version: 1.2.0
4
+ Summary: Python client for the DeFiStream API
5
+ Project-URL: Homepage, https://defistream.dev
6
+ Project-URL: Documentation, https://docs.defistream.dev
7
+ Project-URL: Repository, https://github.com/Eren-Nevin/DeFiStream_PythonClient
8
+ Author-email: DeFiStream <support@defistream.dev>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: api,blockchain,crypto,defi,ethereum,web3
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.9
23
+ Requires-Dist: httpx>=0.25.0
24
+ Requires-Dist: pandas>=2.0.0
25
+ Requires-Dist: pyarrow>=14.0.0
26
+ Requires-Dist: pydantic>=2.0.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
29
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
30
+ Requires-Dist: python-dotenv>=1.0.0; extra == 'dev'
31
+ Provides-Extra: polars
32
+ Requires-Dist: polars>=0.20.0; extra == 'polars'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # DeFiStream Python Client
36
+
37
+ Official Python client for the [DeFiStream API](https://defistream.dev).
38
+
39
+ ## Getting an API Key
40
+
41
+ To use the DeFiStream API, you need to sign up for an account at [defistream.dev](https://defistream.dev) to obtain your API key.
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install defistream
47
+ ```
48
+
49
+ This includes pandas and pyarrow by default for DataFrame support.
50
+
51
+ With polars support (in addition to pandas):
52
+ ```bash
53
+ pip install defistream[polars]
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ ```python
59
+ from defistream import DeFiStream
60
+
61
+ # Initialize client (reads DEFISTREAM_API_KEY from environment if not provided)
62
+ client = DeFiStream()
63
+
64
+ # Or with explicit API key
65
+ client = DeFiStream(api_key="dsk_your_api_key")
66
+
67
+ # Query ERC20 transfers using builder pattern
68
+ df = (
69
+ client.erc20.transfers("USDT")
70
+ .network("ETH")
71
+ .block_range(21000000, 21010000)
72
+ .as_df()
73
+ )
74
+
75
+ print(df.head())
76
+ ```
77
+
78
+ ## Features
79
+
80
+ - **Builder pattern**: Fluent query API with chainable methods
81
+ - **Type-safe**: Full type hints and Pydantic models
82
+ - **Multiple formats**: DataFrame (pandas/polars), CSV, Parquet, JSON
83
+ - **Async support**: Native async/await with `AsyncDeFiStream`
84
+ - **All protocols**: ERC20, AAVE, Uniswap, Lido, Stader, Threshold, Native tokens
85
+
86
+ ## Supported Protocols
87
+
88
+ | Protocol | Events |
89
+ |----------|--------|
90
+ | ERC20 | `transfers` |
91
+ | Native Token | `transfers` |
92
+ | AAVE V3 | `deposits`, `withdrawals`, `borrows`, `repays`, `flashloans`, `liquidations` |
93
+ | Uniswap V3 | `swaps`, `deposits`, `withdrawals`, `collects` |
94
+ | Lido | `deposits`, `withdrawal_requests`, `withdrawals_claimed`, `l2_deposits`, `l2_withdrawal_requests` |
95
+ | Stader | `deposits`, `withdrawal_requests`, `withdrawals` |
96
+ | Threshold | `deposit_requests`, `deposits`, `withdrawal_requests`, `withdrawals` |
97
+
98
+ ## Usage Examples
99
+
100
+ ### Builder Pattern
101
+
102
+ The client uses a fluent builder pattern. The query is only executed when you call a terminal method like `as_df()`, `as_file()`, or `as_dict()`.
103
+
104
+ ```python
105
+ from defistream import DeFiStream
106
+
107
+ client = DeFiStream()
108
+
109
+ # Build query step by step
110
+ query = client.erc20.transfers("USDT")
111
+ query = query.network("ETH")
112
+ query = query.block_range(21000000, 21010000)
113
+ query = query.min_amount(1000)
114
+
115
+ # Execute and get DataFrame
116
+ df = query.as_df()
117
+
118
+ # Or chain everything
119
+ df = (
120
+ client.erc20.transfers("USDT")
121
+ .network("ETH")
122
+ .block_range(21000000, 21010000)
123
+ .min_amount(1000)
124
+ .as_df()
125
+ )
126
+ ```
127
+
128
+ ### ERC20 Transfers
129
+
130
+ ```python
131
+ # Get USDT transfers over 10,000 USDT
132
+ df = (
133
+ client.erc20.transfers("USDT")
134
+ .network("ETH")
135
+ .block_range(21000000, 21010000)
136
+ .min_amount(10000)
137
+ .as_df()
138
+ )
139
+
140
+ # Filter by sender
141
+ df = (
142
+ client.erc20.transfers("USDT")
143
+ .network("ETH")
144
+ .block_range(21000000, 21010000)
145
+ .sender("0x28c6c06298d514db089934071355e5743bf21d60")
146
+ .as_df()
147
+ )
148
+ ```
149
+
150
+ ### AAVE Events
151
+
152
+ ```python
153
+ # Get deposits
154
+ df = (
155
+ client.aave.deposits()
156
+ .network("ETH")
157
+ .block_range(21000000, 21010000)
158
+ .as_df()
159
+ )
160
+
161
+ # Use a specific market type on ETH (Core, Prime, or EtherFi)
162
+ df = (
163
+ client.aave.deposits()
164
+ .network("ETH")
165
+ .block_range(21000000, 21010000)
166
+ .eth_market_type("Prime")
167
+ .as_df()
168
+ )
169
+ ```
170
+
171
+ ### Uniswap Swaps
172
+
173
+ ```python
174
+ # Get swaps for WETH/USDC pool with 0.05% fee tier
175
+ df = (
176
+ client.uniswap.swaps("WETH", "USDC", 500)
177
+ .network("ETH")
178
+ .block_range(21000000, 21010000)
179
+ .as_df()
180
+ )
181
+
182
+ # Or build with chain methods
183
+ df = (
184
+ client.uniswap.swaps()
185
+ .symbol0("WETH")
186
+ .symbol1("USDC")
187
+ .fee(500)
188
+ .network("ETH")
189
+ .block_range(21000000, 21010000)
190
+ .as_df()
191
+ )
192
+ ```
193
+
194
+ ### Native Token Transfers
195
+
196
+ ```python
197
+ # Get ETH transfers >= 1 ETH
198
+ df = (
199
+ client.native_token.transfers()
200
+ .network("ETH")
201
+ .block_range(21000000, 21010000)
202
+ .min_amount(1.0)
203
+ .as_df()
204
+ )
205
+ ```
206
+
207
+ ### Label & Category Filters
208
+
209
+ ```python
210
+ # Get USDT transfers involving Binance wallets
211
+ df = (
212
+ client.erc20.transfers("USDT")
213
+ .network("ETH")
214
+ .block_range(21000000, 21010000)
215
+ .involving_label("Binance")
216
+ .as_df()
217
+ )
218
+
219
+ # Get USDT transfers FROM exchanges TO DeFi protocols
220
+ df = (
221
+ client.erc20.transfers("USDT")
222
+ .network("ETH")
223
+ .block_range(21000000, 21010000)
224
+ .sender_category("exchange")
225
+ .receiver_category("defi")
226
+ .as_df()
227
+ )
228
+
229
+ # Get AAVE deposits involving exchange addresses
230
+ df = (
231
+ client.aave.deposits()
232
+ .network("ETH")
233
+ .block_range(21000000, 21010000)
234
+ .involving_category("exchange")
235
+ .as_df()
236
+ )
237
+
238
+ # Get native ETH transfers FROM Binance or Coinbase (multi-value)
239
+ df = (
240
+ client.native_token.transfers()
241
+ .network("ETH")
242
+ .block_range(21000000, 21010000)
243
+ .sender_label("Binance,Coinbase")
244
+ .as_df()
245
+ )
246
+ ```
247
+
248
+ ### Verbose Mode
249
+
250
+ By default, responses omit metadata fields to reduce payload size. Use `.verbose()` to include all fields:
251
+
252
+ ```python
253
+ # Default: compact response (no tx_hash, tx_id, log_index, network, name)
254
+ df = (
255
+ client.erc20.transfers("USDT")
256
+ .network("ETH")
257
+ .block_range(21000000, 21010000)
258
+ .as_df()
259
+ )
260
+
261
+ # Verbose: includes all metadata fields
262
+ df = (
263
+ client.erc20.transfers("USDT")
264
+ .network("ETH")
265
+ .block_range(21000000, 21010000)
266
+ .verbose()
267
+ .as_df()
268
+ )
269
+ ```
270
+
271
+ ### Return as DataFrame
272
+
273
+ ```python
274
+ # As pandas DataFrame (default)
275
+ df = (
276
+ client.erc20.transfers("USDT")
277
+ .network("ETH")
278
+ .block_range(21000000, 21010000)
279
+ .as_df()
280
+ )
281
+
282
+ # As polars DataFrame
283
+ df = (
284
+ client.erc20.transfers("USDT")
285
+ .network("ETH")
286
+ .block_range(21000000, 21010000)
287
+ .as_df("polars")
288
+ )
289
+ ```
290
+
291
+ ### Save to File
292
+
293
+ Format is automatically determined by file extension:
294
+
295
+ ```python
296
+ # Save as Parquet (recommended for large datasets)
297
+ (
298
+ client.erc20.transfers("USDT")
299
+ .network("ETH")
300
+ .block_range(21000000, 21100000)
301
+ .as_file("transfers.parquet")
302
+ )
303
+
304
+ # Save as CSV
305
+ (
306
+ client.erc20.transfers("USDT")
307
+ .network("ETH")
308
+ .block_range(21000000, 21100000)
309
+ .as_file("transfers.csv")
310
+ )
311
+
312
+ # Save as JSON
313
+ (
314
+ client.erc20.transfers("USDT")
315
+ .network("ETH")
316
+ .block_range(21000000, 21010000)
317
+ .as_file("transfers.json")
318
+ )
319
+ ```
320
+
321
+ ### Return as Dictionary (JSON)
322
+
323
+ For small queries, you can get results as a list of dictionaries:
324
+
325
+ ```python
326
+ transfers = (
327
+ client.erc20.transfers("USDT")
328
+ .network("ETH")
329
+ .block_range(21000000, 21010000)
330
+ .as_dict()
331
+ )
332
+
333
+ for transfer in transfers:
334
+ print(f"{transfer['sender']} -> {transfer['receiver']}: {transfer['amount']}")
335
+ ```
336
+
337
+ > **Note:** `as_dict()` and `as_file("*.json")` use JSON format which has a **10,000 block limit**. For larger block ranges, use `as_df()` or `as_file()` with `.parquet` or `.csv` extensions, which support up to 1,000,000 blocks.
338
+
339
+ ### Context Manager
340
+
341
+ Both sync and async clients support context managers to automatically close connections:
342
+
343
+ ```python
344
+ # Sync
345
+ with DeFiStream() as client:
346
+ df = (
347
+ client.erc20.transfers("USDT")
348
+ .network("ETH")
349
+ .block_range(21000000, 21010000)
350
+ .as_df()
351
+ )
352
+ ```
353
+
354
+ ### Async Usage
355
+
356
+ ```python
357
+ import asyncio
358
+ from defistream import AsyncDeFiStream
359
+
360
+ async def main():
361
+ async with AsyncDeFiStream() as client:
362
+ df = await (
363
+ client.erc20.transfers("USDT")
364
+ .network("ETH")
365
+ .block_range(21000000, 21010000)
366
+ .as_df()
367
+ )
368
+ print(f"Found {len(df)} transfers")
369
+
370
+ asyncio.run(main())
371
+ ```
372
+
373
+ ### List Available Decoders
374
+
375
+ ```python
376
+ client = DeFiStream()
377
+ decoders = client.decoders()
378
+ print(decoders) # ['native_token', 'erc20', 'aave', 'uniswap', 'lido', 'stader', 'threshold']
379
+ ```
380
+
381
+ ## Configuration
382
+
383
+ ### Environment Variables
384
+
385
+ ```bash
386
+ export DEFISTREAM_API_KEY=dsk_your_api_key
387
+ export DEFISTREAM_BASE_URL=https://api.defistream.dev/v1 # optional
388
+ ```
389
+
390
+ ```python
391
+ from defistream import DeFiStream
392
+
393
+ # API key from environment
394
+ client = DeFiStream()
395
+
396
+ # Or explicit
397
+ client = DeFiStream(api_key="dsk_...", base_url="https://api.defistream.dev/v1")
398
+ ```
399
+
400
+ ### Timeout and Retries
401
+
402
+ ```python
403
+ client = DeFiStream(
404
+ api_key="dsk_...",
405
+ timeout=60.0, # seconds
406
+ max_retries=3
407
+ )
408
+ ```
409
+
410
+ ## Error Handling
411
+
412
+ ```python
413
+ from defistream import DeFiStream
414
+ from defistream.exceptions import (
415
+ DeFiStreamError,
416
+ AuthenticationError,
417
+ QuotaExceededError,
418
+ RateLimitError,
419
+ ValidationError
420
+ )
421
+
422
+ client = DeFiStream()
423
+
424
+ try:
425
+ df = (
426
+ client.erc20.transfers("USDT")
427
+ .network("ETH")
428
+ .block_range(21000000, 21010000)
429
+ .as_df()
430
+ )
431
+ except AuthenticationError:
432
+ print("Invalid API key")
433
+ except QuotaExceededError as e:
434
+ print(f"Quota exceeded. Remaining: {e.remaining}")
435
+ except RateLimitError as e:
436
+ print(f"Rate limited. Retry after: {e.retry_after}s")
437
+ except ValidationError as e:
438
+ print(f"Invalid request: {e.message}")
439
+ except DeFiStreamError as e:
440
+ print(f"API error: {e}")
441
+ ```
442
+
443
+ ## Response Headers
444
+
445
+ Access rate limit and quota information:
446
+
447
+ ```python
448
+ df = (
449
+ client.erc20.transfers("USDT")
450
+ .network("ETH")
451
+ .block_range(21000000, 21010000)
452
+ .as_df()
453
+ )
454
+
455
+ # Access response metadata
456
+ print(f"Rate limit: {client.last_response.rate_limit}")
457
+ print(f"Remaining quota: {client.last_response.quota_remaining}")
458
+ print(f"Request cost: {client.last_response.request_cost}")
459
+ ```
460
+
461
+ ## Builder Methods Reference
462
+
463
+ ### Common Methods (all protocols)
464
+
465
+ | Method | Description |
466
+ |--------|-------------|
467
+ | `.network(net)` | Set network (ETH, ARB, BASE, OP, POLYGON, etc.) |
468
+ | `.start_block(n)` | Set starting block number |
469
+ | `.end_block(n)` | Set ending block number |
470
+ | `.block_range(start, end)` | Set both start and end blocks |
471
+ | `.start_time(ts)` | Set starting time (ISO format or Unix timestamp) |
472
+ | `.end_time(ts)` | Set ending time (ISO format or Unix timestamp) |
473
+ | `.time_range(start, end)` | Set both start and end times |
474
+ | `.verbose()` | Include all metadata fields |
475
+
476
+ ### Protocol-Specific Parameters
477
+
478
+ | Method | Protocols | Description |
479
+ |--------|-----------|-------------|
480
+ | `.token(symbol)` | ERC20 | Token symbol (USDT, USDC) or contract address (required) |
481
+ | `.sender(*addrs)` | ERC20, Native | Filter by sender address (multi-value) |
482
+ | `.receiver(*addrs)` | ERC20, Native | Filter by receiver address (multi-value) |
483
+ | `.involving(*addrs)` | All | Filter by any involved address (multi-value) |
484
+ | `.from_address(*addrs)` | ERC20, Native | Alias for `.sender()` |
485
+ | `.to_address(*addrs)` | ERC20, Native | Alias for `.receiver()` |
486
+ | `.min_amount(amt)` | ERC20, Native | Minimum transfer amount |
487
+ | `.max_amount(amt)` | ERC20, Native | Maximum transfer amount |
488
+ | `.eth_market_type(type)` | AAVE | Market type for ETH: 'Core', 'Prime', 'EtherFi' |
489
+ | `.symbol0(sym)` | Uniswap | First token symbol (required) |
490
+ | `.symbol1(sym)` | Uniswap | Second token symbol (required) |
491
+ | `.fee(tier)` | Uniswap | Fee tier: 100, 500, 3000, 10000 (required) |
492
+
493
+ ### Address Label & Category Filters
494
+
495
+ Filter events by entity names or categories using the labels database. Available on all protocols.
496
+
497
+ | Method | Protocols | Description |
498
+ |--------|-----------|-------------|
499
+ | `.involving_label(label)` | All | Filter where any involved address matches a label substring (e.g., "Binance") |
500
+ | `.involving_category(cat)` | All | Filter where any involved address matches a category (e.g., "exchange") |
501
+ | `.sender_label(label)` | ERC20, Native | Filter sender by label substring |
502
+ | `.sender_category(cat)` | ERC20, Native | Filter sender by category |
503
+ | `.receiver_label(label)` | ERC20, Native | Filter receiver by label substring |
504
+ | `.receiver_category(cat)` | ERC20, Native | Filter receiver by category |
505
+
506
+ **Multi-value support:** Pass multiple values as separate arguments (e.g., `.sender_label("Binance", "Coinbase")`) or as a comma-separated string (e.g., `.sender_label("Binance,Coinbase")`). Both forms are equivalent.
507
+
508
+ **Mutual exclusivity:** Within each slot (involving/sender/receiver), only one of address/label/category can be set. `involving*` filters cannot be combined with `sender*`/`receiver*` filters.
509
+
510
+ ### Terminal Methods
511
+
512
+ | Method | Description |
513
+ |--------|-------------|
514
+ | `.as_df()` | Execute and return pandas DataFrame |
515
+ | `.as_df("polars")` | Execute and return polars DataFrame |
516
+ | `.as_file(path)` | Execute and save to file (format from extension) |
517
+ | `.as_file(path, format="csv")` | Execute and save with explicit format |
518
+ | `.as_dict()` | Execute and return list of dicts (JSON, 10K block limit) |
519
+
520
+ ## License
521
+
522
+ MIT License