defistream 1.0.0__tar.gz → 1.0.2__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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: defistream
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: Python client for the DeFiStream API
5
5
  Project-URL: Homepage, https://defistream.dev
6
6
  Project-URL: Documentation, https://docs.defistream.dev
@@ -34,7 +34,11 @@ Description-Content-Type: text/markdown
34
34
 
35
35
  # DeFiStream Python Client
36
36
 
37
- Official Python client for the [DeFiStream API](https://defistream.dev) - access historical DeFi events from 45+ EVM networks.
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.
38
42
 
39
43
  ## Installation
40
44
 
@@ -61,44 +65,41 @@ client = DeFiStream()
61
65
  client = DeFiStream(api_key="dsk_your_api_key")
62
66
 
63
67
  # Query ERC20 transfers using builder pattern
64
- transfers = (
68
+ df = (
65
69
  client.erc20.transfers("USDT")
66
70
  .network("ETH")
67
- .start_block(24000000)
68
- .end_block(24100000)
69
- .as_dict()
71
+ .block_range(21000000, 21010000)
72
+ .as_df()
70
73
  )
71
74
 
72
- for transfer in transfers:
73
- print(f"{transfer['sender']} -> {transfer['receiver']}: {transfer['amount']}")
75
+ print(df.head())
74
76
  ```
75
77
 
76
78
  ## Features
77
79
 
78
80
  - **Builder pattern**: Fluent query API with chainable methods
79
81
  - **Type-safe**: Full type hints and Pydantic models
80
- - **Multiple formats**: JSON, CSV, Parquet, pandas DataFrame, polars DataFrame
82
+ - **Multiple formats**: DataFrame (pandas/polars), CSV, Parquet, JSON
81
83
  - **Async support**: Native async/await with `AsyncDeFiStream`
82
- - **All protocols**: AAVE, Uniswap, Lido, ERC20, Native tokens, and more
83
- - **Verbose mode**: Include all metadata fields (tx_hash, tx_id, log_index, network, name)
84
+ - **All protocols**: ERC20, AAVE, Uniswap, Lido, Stader, Threshold, Native tokens
84
85
 
85
86
  ## Supported Protocols
86
87
 
87
88
  | Protocol | Events |
88
89
  |----------|--------|
89
- | ERC20 | `transfers`, `approvals` |
90
+ | ERC20 | `transfers` |
90
91
  | Native Token | `transfers` |
91
- | AAVE V3 | `deposits`, `withdrawals`, `borrows`, `repays`, `liquidations` |
92
- | Uniswap V3 | `swaps`, `mints`, `burns` |
93
- | Lido | `deposits`, `withdrawals` |
94
- | Stader | `deposits`, `withdrawals` |
95
- | Threshold | `mints`, `burns` |
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` |
96
97
 
97
98
  ## Usage Examples
98
99
 
99
100
  ### Builder Pattern
100
101
 
101
- The client uses a fluent builder pattern. The query is only executed when you call a terminal method like `as_dict()`, `as_df()`, or `as_file()`.
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()`.
102
103
 
103
104
  ```python
104
105
  from defistream import DeFiStream
@@ -108,21 +109,19 @@ client = DeFiStream()
108
109
  # Build query step by step
109
110
  query = client.erc20.transfers("USDT")
110
111
  query = query.network("ETH")
111
- query = query.start_block(24000000)
112
- query = query.end_block(24100000)
112
+ query = query.block_range(21000000, 21010000)
113
113
  query = query.min_amount(1000)
114
114
 
115
- # Execute and get results
116
- transfers = query.as_dict()
115
+ # Execute and get DataFrame
116
+ df = query.as_df()
117
117
 
118
118
  # Or chain everything
119
- transfers = (
119
+ df = (
120
120
  client.erc20.transfers("USDT")
121
121
  .network("ETH")
122
- .start_block(24000000)
123
- .end_block(24100000)
122
+ .block_range(21000000, 21010000)
124
123
  .min_amount(1000)
125
- .as_dict()
124
+ .as_df()
126
125
  )
127
126
  ```
128
127
 
@@ -130,35 +129,21 @@ transfers = (
130
129
 
131
130
  ```python
132
131
  # Get USDT transfers over 10,000 USDT
133
- transfers = (
132
+ df = (
134
133
  client.erc20.transfers("USDT")
135
134
  .network("ETH")
136
- .start_block(24000000)
137
- .end_block(24100000)
135
+ .block_range(21000000, 21010000)
138
136
  .min_amount(10000)
139
- .as_dict()
137
+ .as_df()
140
138
  )
141
139
 
142
140
  # Filter by sender
143
- transfers = (
141
+ df = (
144
142
  client.erc20.transfers("USDT")
145
143
  .network("ETH")
146
- .start_block(24000000)
147
- .end_block(24100000)
144
+ .block_range(21000000, 21010000)
148
145
  .sender("0x28c6c06298d514db089934071355e5743bf21d60")
149
- .as_dict()
150
- )
151
-
152
- # Or use aliases: from_address/to_address
153
- transfers = (
154
- client.erc20.transfers()
155
- .network("ETH")
156
- .start_block(24000000)
157
- .end_block(24100000)
158
- .token("USDC")
159
- .from_address("0x...")
160
- .to_address("0x...")
161
- .as_dict()
146
+ .as_df()
162
147
  )
163
148
  ```
164
149
 
@@ -166,22 +151,20 @@ transfers = (
166
151
 
167
152
  ```python
168
153
  # Get deposits
169
- deposits = (
154
+ df = (
170
155
  client.aave.deposits()
171
156
  .network("ETH")
172
- .start_block(24000000)
173
- .end_block(24100000)
174
- .as_dict()
157
+ .block_range(21000000, 21010000)
158
+ .as_df()
175
159
  )
176
160
 
177
- # Get liquidations for a specific user
178
- liquidations = (
179
- client.aave.liquidations()
161
+ # Use a specific market type on ETH (Core, Prime, or EtherFi)
162
+ df = (
163
+ client.aave.deposits()
180
164
  .network("ETH")
181
- .start_block(24000000)
182
- .end_block(24100000)
183
- .user("0x...")
184
- .as_dict()
165
+ .block_range(21000000, 21010000)
166
+ .eth_market_type("Prime")
167
+ .as_df()
185
168
  )
186
169
  ```
187
170
 
@@ -189,24 +172,22 @@ liquidations = (
189
172
 
190
173
  ```python
191
174
  # Get swaps for WETH/USDC pool with 0.05% fee tier
192
- swaps = (
175
+ df = (
193
176
  client.uniswap.swaps("WETH", "USDC", 500)
194
177
  .network("ETH")
195
- .start_block(24000000)
196
- .end_block(24100000)
197
- .as_dict()
178
+ .block_range(21000000, 21010000)
179
+ .as_df()
198
180
  )
199
181
 
200
182
  # Or build with chain methods
201
- swaps = (
183
+ df = (
202
184
  client.uniswap.swaps()
203
185
  .symbol0("WETH")
204
186
  .symbol1("USDC")
205
187
  .fee(500)
206
188
  .network("ETH")
207
- .start_block(24000000)
208
- .end_block(24100000)
209
- .as_dict()
189
+ .block_range(21000000, 21010000)
190
+ .as_df()
210
191
  )
211
192
  ```
212
193
 
@@ -214,13 +195,12 @@ swaps = (
214
195
 
215
196
  ```python
216
197
  # Get ETH transfers >= 1 ETH
217
- transfers = (
198
+ df = (
218
199
  client.native_token.transfers()
219
200
  .network("ETH")
220
- .start_block(24000000)
221
- .end_block(24100000)
201
+ .block_range(21000000, 21010000)
222
202
  .min_amount(1.0)
223
- .as_dict()
203
+ .as_df()
224
204
  )
225
205
  ```
226
206
 
@@ -230,25 +210,21 @@ By default, responses omit metadata fields to reduce payload size. Use `.verbose
230
210
 
231
211
  ```python
232
212
  # Default: compact response (no tx_hash, tx_id, log_index, network, name)
233
- transfers = (
213
+ df = (
234
214
  client.erc20.transfers("USDT")
235
215
  .network("ETH")
236
- .start_block(24000000)
237
- .end_block(24100000)
238
- .as_dict()
216
+ .block_range(21000000, 21010000)
217
+ .as_df()
239
218
  )
240
- # Returns: [{"block_number": 24000050, "sender": "0x...", "receiver": "0x...", "amount": 1000.0, ...}]
241
219
 
242
220
  # Verbose: includes all metadata fields
243
- transfers = (
221
+ df = (
244
222
  client.erc20.transfers("USDT")
245
223
  .network("ETH")
246
- .start_block(24000000)
247
- .end_block(24100000)
224
+ .block_range(21000000, 21010000)
248
225
  .verbose()
249
- .as_dict()
226
+ .as_df()
250
227
  )
251
- # Returns: [{"name": "TransferEvent", "network": "ETH", "tx_id": "0x...", "tx_hash": "0x...", "log_index": 5, "block_number": 24000050, ...}]
252
228
  ```
253
229
 
254
230
  ### Return as DataFrame
@@ -258,8 +234,7 @@ transfers = (
258
234
  df = (
259
235
  client.erc20.transfers("USDT")
260
236
  .network("ETH")
261
- .start_block(24000000)
262
- .end_block(24100000)
237
+ .block_range(21000000, 21010000)
263
238
  .as_df()
264
239
  )
265
240
 
@@ -267,8 +242,7 @@ df = (
267
242
  df = (
268
243
  client.erc20.transfers("USDT")
269
244
  .network("ETH")
270
- .start_block(24000000)
271
- .end_block(24100000)
245
+ .block_range(21000000, 21010000)
272
246
  .as_df("polars")
273
247
  )
274
248
  ```
@@ -278,43 +252,49 @@ df = (
278
252
  Format is automatically determined by file extension:
279
253
 
280
254
  ```python
281
- # Save as CSV
255
+ # Save as Parquet (recommended for large datasets)
282
256
  (
283
257
  client.erc20.transfers("USDT")
284
258
  .network("ETH")
285
- .start_block(24000000)
286
- .end_block(24100000)
287
- .as_file("transfers.csv")
259
+ .block_range(21000000, 21100000)
260
+ .as_file("transfers.parquet")
288
261
  )
289
262
 
290
- # Save as Parquet
263
+ # Save as CSV
291
264
  (
292
265
  client.erc20.transfers("USDT")
293
266
  .network("ETH")
294
- .start_block(24000000)
295
- .end_block(24100000)
296
- .as_file("transfers.parquet")
267
+ .block_range(21000000, 21100000)
268
+ .as_file("transfers.csv")
297
269
  )
298
270
 
299
271
  # Save as JSON
300
272
  (
301
273
  client.erc20.transfers("USDT")
302
274
  .network("ETH")
303
- .start_block(24000000)
304
- .end_block(24100000)
275
+ .block_range(21000000, 21010000)
305
276
  .as_file("transfers.json")
306
277
  )
278
+ ```
307
279
 
308
- # Explicit format (when path has no extension)
309
- (
280
+ ### Return as Dictionary (JSON)
281
+
282
+ For small queries, you can get results as a list of dictionaries:
283
+
284
+ ```python
285
+ transfers = (
310
286
  client.erc20.transfers("USDT")
311
287
  .network("ETH")
312
- .start_block(24000000)
313
- .end_block(24100000)
314
- .as_file("transfers", format="csv")
288
+ .block_range(21000000, 21010000)
289
+ .as_dict()
315
290
  )
291
+
292
+ for transfer in transfers:
293
+ print(f"{transfer['sender']} -> {transfer['receiver']}: {transfer['amount']}")
316
294
  ```
317
295
 
296
+ > **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.
297
+
318
298
  ### Async Usage
319
299
 
320
300
  ```python
@@ -323,41 +303,17 @@ from defistream import AsyncDeFiStream
323
303
 
324
304
  async def main():
325
305
  async with AsyncDeFiStream() as client:
326
- transfers = await (
306
+ df = await (
327
307
  client.erc20.transfers("USDT")
328
308
  .network("ETH")
329
- .start_block(24000000)
330
- .end_block(24100000)
331
- .as_dict()
309
+ .block_range(21000000, 21010000)
310
+ .as_df()
332
311
  )
333
- print(f"Found {len(transfers)} transfers")
312
+ print(f"Found {len(df)} transfers")
334
313
 
335
314
  asyncio.run(main())
336
315
  ```
337
316
 
338
- ### Multiple Networks in Parallel
339
-
340
- ```python
341
- import asyncio
342
- from defistream import AsyncDeFiStream
343
-
344
- async def fetch_all_networks():
345
- async with AsyncDeFiStream() as client:
346
- networks = ["ETH", "ARB", "BASE", "OP"]
347
- tasks = [
348
- client.erc20.transfers("USDC")
349
- .network(net)
350
- .start_block(24000000)
351
- .end_block(24100000)
352
- .as_dict()
353
- for net in networks
354
- ]
355
- results = await asyncio.gather(*tasks)
356
- return dict(zip(networks, results))
357
-
358
- all_transfers = asyncio.run(fetch_all_networks())
359
- ```
360
-
361
317
  ## Configuration
362
318
 
363
319
  ### Environment Variables
@@ -402,12 +358,11 @@ from defistream.exceptions import (
402
358
  client = DeFiStream()
403
359
 
404
360
  try:
405
- transfers = (
361
+ df = (
406
362
  client.erc20.transfers("USDT")
407
363
  .network("ETH")
408
- .start_block(24000000)
409
- .end_block(24100000)
410
- .as_dict()
364
+ .block_range(21000000, 21010000)
365
+ .as_df()
411
366
  )
412
367
  except AuthenticationError:
413
368
  print("Invalid API key")
@@ -426,12 +381,11 @@ except DeFiStreamError as e:
426
381
  Access rate limit and quota information:
427
382
 
428
383
  ```python
429
- transfers = (
384
+ df = (
430
385
  client.erc20.transfers("USDT")
431
386
  .network("ETH")
432
- .start_block(24000000)
433
- .end_block(24100000)
434
- .as_dict()
387
+ .block_range(21000000, 21010000)
388
+ .as_df()
435
389
  )
436
390
 
437
391
  # Access response metadata
@@ -446,7 +400,7 @@ print(f"Request cost: {client.last_response.request_cost}")
446
400
 
447
401
  | Method | Description |
448
402
  |--------|-------------|
449
- | `.network(net)` | Set network (ETH, ARB, BASE, OP, etc.) |
403
+ | `.network(net)` | Set network (ETH, ARB, BASE, OP, POLYGON, etc.) |
450
404
  | `.start_block(n)` | Set starting block number |
451
405
  | `.end_block(n)` | Set ending block number |
452
406
  | `.block_range(start, end)` | Set both start and end blocks |
@@ -455,35 +409,30 @@ print(f"Request cost: {client.last_response.request_cost}")
455
409
  | `.time_range(start, end)` | Set both start and end times |
456
410
  | `.verbose()` | Include all metadata fields |
457
411
 
458
- ### Filter Methods
412
+ ### Protocol-Specific Parameters
459
413
 
460
414
  | Method | Protocols | Description |
461
415
  |--------|-----------|-------------|
416
+ | `.token(symbol)` | ERC20 | Token symbol (USDT, USDC) or contract address |
417
+ | `.decimals(n)` | ERC20 | Token decimals when using custom address (default: 18) |
462
418
  | `.sender(addr)` | ERC20, Native | Filter by sender address |
463
419
  | `.receiver(addr)` | ERC20, Native | Filter by receiver address |
464
- | `.from_address(addr)` | ERC20, Native | Alias for sender |
465
- | `.to_address(addr)` | ERC20, Native | Alias for receiver |
466
420
  | `.min_amount(amt)` | ERC20, Native | Minimum transfer amount |
467
- | `.token(symbol)` | ERC20 | Token symbol (USDT, USDC, etc.) |
468
- | `.owner(addr)` | ERC20 Approvals, Lido | Filter by owner |
469
- | `.spender(addr)` | ERC20 Approvals | Filter by spender |
470
- | `.user(addr)` | AAVE | Filter by user |
471
- | `.reserve(addr)` | AAVE | Filter by reserve |
472
- | `.liquidator(addr)` | AAVE Liquidations | Filter by liquidator |
473
- | `.symbol0(sym)` | Uniswap | First token symbol |
474
- | `.symbol1(sym)` | Uniswap | Second token symbol |
475
- | `.fee(tier)` | Uniswap | Fee tier (100, 500, 3000, 10000) |
476
- | `.pool(addr)` | Uniswap | Pool address |
421
+ | `.max_amount(amt)` | ERC20, Native | Maximum transfer amount |
422
+ | `.eth_market_type(type)` | AAVE | Market type for ETH: 'Core', 'Prime', 'EtherFi' |
423
+ | `.symbol0(sym)` | Uniswap | First token symbol (required) |
424
+ | `.symbol1(sym)` | Uniswap | Second token symbol (required) |
425
+ | `.fee(tier)` | Uniswap | Fee tier: 100, 500, 3000, 10000 (required) |
477
426
 
478
427
  ### Terminal Methods
479
428
 
480
429
  | Method | Description |
481
430
  |--------|-------------|
482
- | `.as_dict()` | Execute and return list of dicts (JSON) |
483
431
  | `.as_df()` | Execute and return pandas DataFrame |
484
432
  | `.as_df("polars")` | Execute and return polars DataFrame |
485
433
  | `.as_file(path)` | Execute and save to file (format from extension) |
486
434
  | `.as_file(path, format="csv")` | Execute and save with explicit format |
435
+ | `.as_dict()` | Execute and return list of dicts (JSON, 10K block limit) |
487
436
 
488
437
  ## License
489
438