defistream 1.0.1__tar.gz → 1.0.3__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.1
3
+ Version: 1.0.3
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
@@ -158,12 +158,12 @@ df = (
158
158
  .as_df()
159
159
  )
160
160
 
161
- # Get liquidations for a specific user
161
+ # Use a specific market type on ETH (Core, Prime, or EtherFi)
162
162
  df = (
163
- client.aave.liquidations()
163
+ client.aave.deposits()
164
164
  .network("ETH")
165
165
  .block_range(21000000, 21010000)
166
- .user("0x...")
166
+ .eth_market_type("Prime")
167
167
  .as_df()
168
168
  )
169
169
  ```
@@ -409,23 +409,19 @@ print(f"Request cost: {client.last_response.request_cost}")
409
409
  | `.time_range(start, end)` | Set both start and end times |
410
410
  | `.verbose()` | Include all metadata fields |
411
411
 
412
- ### Filter Methods
412
+ ### Protocol-Specific Parameters
413
413
 
414
414
  | Method | Protocols | Description |
415
415
  |--------|-----------|-------------|
416
+ | `.token(symbol)` | ERC20 | Token symbol (USDT, USDC) or contract address |
416
417
  | `.sender(addr)` | ERC20, Native | Filter by sender address |
417
418
  | `.receiver(addr)` | ERC20, Native | Filter by receiver address |
418
- | `.from_address(addr)` | ERC20, Native | Alias for sender |
419
- | `.to_address(addr)` | ERC20, Native | Alias for receiver |
420
419
  | `.min_amount(amt)` | ERC20, Native | Minimum transfer amount |
421
- | `.token(symbol)` | ERC20 | Token symbol (USDT, USDC, etc.) |
422
- | `.user(addr)` | AAVE | Filter by user |
423
- | `.reserve(addr)` | AAVE | Filter by reserve |
424
- | `.liquidator(addr)` | AAVE Liquidations | Filter by liquidator |
425
- | `.symbol0(sym)` | Uniswap | First token symbol |
426
- | `.symbol1(sym)` | Uniswap | Second token symbol |
427
- | `.fee(tier)` | Uniswap | Fee tier (100, 500, 3000, 10000) |
428
- | `.pool(addr)` | Uniswap | Pool address |
420
+ | `.max_amount(amt)` | ERC20, Native | Maximum transfer amount |
421
+ | `.eth_market_type(type)` | AAVE | Market type for ETH: 'Core', 'Prime', 'EtherFi' |
422
+ | `.symbol0(sym)` | Uniswap | First token symbol (required) |
423
+ | `.symbol1(sym)` | Uniswap | Second token symbol (required) |
424
+ | `.fee(tier)` | Uniswap | Fee tier: 100, 500, 3000, 10000 (required) |
429
425
 
430
426
  ### Terminal Methods
431
427
 
@@ -124,12 +124,12 @@ df = (
124
124
  .as_df()
125
125
  )
126
126
 
127
- # Get liquidations for a specific user
127
+ # Use a specific market type on ETH (Core, Prime, or EtherFi)
128
128
  df = (
129
- client.aave.liquidations()
129
+ client.aave.deposits()
130
130
  .network("ETH")
131
131
  .block_range(21000000, 21010000)
132
- .user("0x...")
132
+ .eth_market_type("Prime")
133
133
  .as_df()
134
134
  )
135
135
  ```
@@ -375,23 +375,19 @@ print(f"Request cost: {client.last_response.request_cost}")
375
375
  | `.time_range(start, end)` | Set both start and end times |
376
376
  | `.verbose()` | Include all metadata fields |
377
377
 
378
- ### Filter Methods
378
+ ### Protocol-Specific Parameters
379
379
 
380
380
  | Method | Protocols | Description |
381
381
  |--------|-----------|-------------|
382
+ | `.token(symbol)` | ERC20 | Token symbol (USDT, USDC) or contract address |
382
383
  | `.sender(addr)` | ERC20, Native | Filter by sender address |
383
384
  | `.receiver(addr)` | ERC20, Native | Filter by receiver address |
384
- | `.from_address(addr)` | ERC20, Native | Alias for sender |
385
- | `.to_address(addr)` | ERC20, Native | Alias for receiver |
386
385
  | `.min_amount(amt)` | ERC20, Native | Minimum transfer amount |
387
- | `.token(symbol)` | ERC20 | Token symbol (USDT, USDC, etc.) |
388
- | `.user(addr)` | AAVE | Filter by user |
389
- | `.reserve(addr)` | AAVE | Filter by reserve |
390
- | `.liquidator(addr)` | AAVE Liquidations | Filter by liquidator |
391
- | `.symbol0(sym)` | Uniswap | First token symbol |
392
- | `.symbol1(sym)` | Uniswap | Second token symbol |
393
- | `.fee(tier)` | Uniswap | Fee tier (100, 500, 3000, 10000) |
394
- | `.pool(addr)` | Uniswap | Pool address |
386
+ | `.max_amount(amt)` | ERC20, Native | Maximum transfer amount |
387
+ | `.eth_market_type(type)` | AAVE | Market type for ETH: 'Core', 'Prime', 'EtherFi' |
388
+ | `.symbol0(sym)` | Uniswap | First token symbol (required) |
389
+ | `.symbol1(sym)` | Uniswap | Second token symbol (required) |
390
+ | `.fee(tier)` | Uniswap | Fee tier: 100, 500, 3000, 10000 (required) |
395
391
 
396
392
  ### Terminal Methods
397
393
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "defistream"
7
- version = "1.0.1"
7
+ version = "1.0.3"
8
8
  description = "Python client for the DeFiStream API"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -45,7 +45,7 @@ from .models import (
45
45
  )
46
46
  from .query import AsyncQueryBuilder, QueryBuilder
47
47
 
48
- __version__ = "1.0.1"
48
+ __version__ = "1.0.3"
49
49
 
50
50
  __all__ = [
51
51
  # Clients
@@ -2,13 +2,11 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import TYPE_CHECKING, Any, Generic, TypeVar
5
+ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  if TYPE_CHECKING:
8
8
  from .client import BaseClient
9
9
 
10
- T = TypeVar("T")
11
-
12
10
 
13
11
  class QueryBuilder:
14
12
  """
@@ -20,7 +18,7 @@ class QueryBuilder:
20
18
  - as_file() - saves to CSV, Parquet, or JSON file
21
19
 
22
20
  Example:
23
- query = client.erc20.transfers("USDT").network("ETH").start_block(24000000).end_block(24100000)
21
+ query = client.erc20.transfers("USDT").network("ETH").block_range(21000000, 21010000)
24
22
  query = query.min_amount(1000).sender("0x...")
25
23
  df = query.as_df() # pandas DataFrame
26
24
  df = query.as_df("polars") # polars DataFrame
@@ -51,7 +49,7 @@ class QueryBuilder:
51
49
 
52
50
  # Network and block range
53
51
  def network(self, network: str) -> "QueryBuilder":
54
- """Set the network (ETH, ARB, BASE, OP, etc.)."""
52
+ """Set the network (ETH, ARB, BASE, OP, POLYGON, etc.)."""
55
53
  return self._copy_with(network=network)
56
54
 
57
55
  def start_block(self, block: int) -> "QueryBuilder":
@@ -79,13 +77,13 @@ class QueryBuilder:
79
77
  """Set both start and end times."""
80
78
  return self._copy_with(since=start, until=end)
81
79
 
82
- # Common filters
80
+ # ERC20 and Native Token filters
83
81
  def sender(self, address: str) -> "QueryBuilder":
84
- """Filter by sender address."""
82
+ """Filter by sender address (ERC20, Native Token)."""
85
83
  return self._copy_with(sender=address)
86
84
 
87
85
  def receiver(self, address: str) -> "QueryBuilder":
88
- """Filter by receiver address."""
86
+ """Filter by receiver address (ERC20, Native Token)."""
89
87
  return self._copy_with(receiver=address)
90
88
 
91
89
  def from_address(self, address: str) -> "QueryBuilder":
@@ -97,52 +95,36 @@ class QueryBuilder:
97
95
  return self.receiver(address)
98
96
 
99
97
  def min_amount(self, amount: float) -> "QueryBuilder":
100
- """Filter by minimum amount."""
98
+ """Filter by minimum amount (ERC20, Native Token)."""
101
99
  return self._copy_with(min_amount=amount)
102
100
 
101
+ def max_amount(self, amount: float) -> "QueryBuilder":
102
+ """Filter by maximum amount (ERC20, Native Token)."""
103
+ return self._copy_with(max_amount=amount)
104
+
103
105
  # ERC20 specific
104
106
  def token(self, symbol: str) -> "QueryBuilder":
105
- """Set token symbol (for ERC20)."""
107
+ """Set token symbol or address (ERC20)."""
106
108
  return self._copy_with(token=symbol)
107
109
 
108
- def owner(self, address: str) -> "QueryBuilder":
109
- """Filter by owner address (for approvals)."""
110
- return self._copy_with(owner=address)
111
-
112
- def spender(self, address: str) -> "QueryBuilder":
113
- """Filter by spender address (for approvals)."""
114
- return self._copy_with(spender=address)
115
-
116
110
  # AAVE specific
117
- def user(self, address: str) -> "QueryBuilder":
118
- """Filter by user address (for AAVE)."""
119
- return self._copy_with(user=address)
120
-
121
- def reserve(self, address: str) -> "QueryBuilder":
122
- """Filter by reserve address (for AAVE)."""
123
- return self._copy_with(reserve=address)
124
-
125
- def liquidator(self, address: str) -> "QueryBuilder":
126
- """Filter by liquidator address (for AAVE liquidations)."""
127
- return self._copy_with(liquidator=address)
111
+ def eth_market_type(self, market_type: str) -> "QueryBuilder":
112
+ """Set AAVE market type for ETH network: 'Core', 'Prime', or 'EtherFi'. Default: 'Core'."""
113
+ return self._copy_with(eth_market_type=market_type)
128
114
 
129
115
  # Uniswap specific
130
116
  def symbol0(self, symbol: str) -> "QueryBuilder":
131
- """Set first token symbol (for Uniswap)."""
117
+ """Set first token symbol (Uniswap)."""
132
118
  return self._copy_with(symbol0=symbol)
133
119
 
134
120
  def symbol1(self, symbol: str) -> "QueryBuilder":
135
- """Set second token symbol (for Uniswap)."""
121
+ """Set second token symbol (Uniswap)."""
136
122
  return self._copy_with(symbol1=symbol)
137
123
 
138
124
  def fee(self, fee_tier: int) -> "QueryBuilder":
139
- """Set fee tier (for Uniswap): 100, 500, 3000, 10000."""
125
+ """Set fee tier (Uniswap): 100, 500, 3000, 10000."""
140
126
  return self._copy_with(fee=fee_tier)
141
127
 
142
- def pool(self, address: str) -> "QueryBuilder":
143
- """Set pool address (for Uniswap)."""
144
- return self._copy_with(pool=address)
145
-
146
128
  # Verbose mode
147
129
  def verbose(self, enabled: bool = True) -> "QueryBuilder":
148
130
  """Include all metadata fields (tx_hash, tx_id, log_index, network, name)."""
@@ -161,7 +143,7 @@ class QueryBuilder:
161
143
  """
162
144
  Execute query and return results as list of dictionaries.
163
145
 
164
- Uses JSON format from API.
146
+ Uses JSON format from API. Limited to 10,000 blocks.
165
147
 
166
148
  Returns:
167
149
  List of event dictionaries
@@ -253,7 +235,7 @@ class AsyncQueryBuilder:
253
235
  - as_file() - saves to CSV, Parquet, or JSON file
254
236
 
255
237
  Example:
256
- query = client.erc20.transfers("USDT").network("ETH").start_block(24000000).end_block(24100000)
238
+ query = client.erc20.transfers("USDT").network("ETH").block_range(21000000, 21010000)
257
239
  df = await query.as_df() # pandas DataFrame
258
240
  df = await query.as_df("polars") # polars DataFrame
259
241
  await query.as_file("transfers.csv") # save to CSV
@@ -283,7 +265,7 @@ class AsyncQueryBuilder:
283
265
 
284
266
  # Network and block range
285
267
  def network(self, network: str) -> "AsyncQueryBuilder":
286
- """Set the network (ETH, ARB, BASE, OP, etc.)."""
268
+ """Set the network (ETH, ARB, BASE, OP, POLYGON, etc.)."""
287
269
  return self._copy_with(network=network)
288
270
 
289
271
  def start_block(self, block: int) -> "AsyncQueryBuilder":
@@ -311,13 +293,13 @@ class AsyncQueryBuilder:
311
293
  """Set both start and end times."""
312
294
  return self._copy_with(since=start, until=end)
313
295
 
314
- # Common filters
296
+ # ERC20 and Native Token filters
315
297
  def sender(self, address: str) -> "AsyncQueryBuilder":
316
- """Filter by sender address."""
298
+ """Filter by sender address (ERC20, Native Token)."""
317
299
  return self._copy_with(sender=address)
318
300
 
319
301
  def receiver(self, address: str) -> "AsyncQueryBuilder":
320
- """Filter by receiver address."""
302
+ """Filter by receiver address (ERC20, Native Token)."""
321
303
  return self._copy_with(receiver=address)
322
304
 
323
305
  def from_address(self, address: str) -> "AsyncQueryBuilder":
@@ -329,52 +311,36 @@ class AsyncQueryBuilder:
329
311
  return self.receiver(address)
330
312
 
331
313
  def min_amount(self, amount: float) -> "AsyncQueryBuilder":
332
- """Filter by minimum amount."""
314
+ """Filter by minimum amount (ERC20, Native Token)."""
333
315
  return self._copy_with(min_amount=amount)
334
316
 
317
+ def max_amount(self, amount: float) -> "AsyncQueryBuilder":
318
+ """Filter by maximum amount (ERC20, Native Token)."""
319
+ return self._copy_with(max_amount=amount)
320
+
335
321
  # ERC20 specific
336
322
  def token(self, symbol: str) -> "AsyncQueryBuilder":
337
- """Set token symbol (for ERC20)."""
323
+ """Set token symbol or address (ERC20)."""
338
324
  return self._copy_with(token=symbol)
339
325
 
340
- def owner(self, address: str) -> "AsyncQueryBuilder":
341
- """Filter by owner address (for approvals)."""
342
- return self._copy_with(owner=address)
343
-
344
- def spender(self, address: str) -> "AsyncQueryBuilder":
345
- """Filter by spender address (for approvals)."""
346
- return self._copy_with(spender=address)
347
-
348
326
  # AAVE specific
349
- def user(self, address: str) -> "AsyncQueryBuilder":
350
- """Filter by user address (for AAVE)."""
351
- return self._copy_with(user=address)
352
-
353
- def reserve(self, address: str) -> "AsyncQueryBuilder":
354
- """Filter by reserve address (for AAVE)."""
355
- return self._copy_with(reserve=address)
356
-
357
- def liquidator(self, address: str) -> "AsyncQueryBuilder":
358
- """Filter by liquidator address (for AAVE liquidations)."""
359
- return self._copy_with(liquidator=address)
327
+ def eth_market_type(self, market_type: str) -> "AsyncQueryBuilder":
328
+ """Set AAVE market type for ETH network: 'Core', 'Prime', or 'EtherFi'. Default: 'Core'."""
329
+ return self._copy_with(eth_market_type=market_type)
360
330
 
361
331
  # Uniswap specific
362
332
  def symbol0(self, symbol: str) -> "AsyncQueryBuilder":
363
- """Set first token symbol (for Uniswap)."""
333
+ """Set first token symbol (Uniswap)."""
364
334
  return self._copy_with(symbol0=symbol)
365
335
 
366
336
  def symbol1(self, symbol: str) -> "AsyncQueryBuilder":
367
- """Set second token symbol (for Uniswap)."""
337
+ """Set second token symbol (Uniswap)."""
368
338
  return self._copy_with(symbol1=symbol)
369
339
 
370
340
  def fee(self, fee_tier: int) -> "AsyncQueryBuilder":
371
- """Set fee tier (for Uniswap): 100, 500, 3000, 10000."""
341
+ """Set fee tier (Uniswap): 100, 500, 3000, 10000."""
372
342
  return self._copy_with(fee=fee_tier)
373
343
 
374
- def pool(self, address: str) -> "AsyncQueryBuilder":
375
- """Set pool address (for Uniswap)."""
376
- return self._copy_with(pool=address)
377
-
378
344
  # Verbose mode
379
345
  def verbose(self, enabled: bool = True) -> "AsyncQueryBuilder":
380
346
  """Include all metadata fields (tx_hash, tx_id, log_index, network, name)."""
@@ -393,7 +359,7 @@ class AsyncQueryBuilder:
393
359
  """
394
360
  Execute query and return results as list of dictionaries.
395
361
 
396
- Uses JSON format from API.
362
+ Uses JSON format from API. Limited to 10,000 blocks.
397
363
 
398
364
  Returns:
399
365
  List of event dictionaries
@@ -405,8 +371,6 @@ class AsyncQueryBuilder:
405
371
  """
406
372
  Execute query and return results as DataFrame.
407
373
 
408
- Uses Parquet format from API for efficiency, then converts to DataFrame.
409
-
410
374
  Args:
411
375
  library: DataFrame library to use - "pandas" (default) or "polars"
412
376
 
@@ -221,6 +221,12 @@ class TestBuilderPattern:
221
221
  query = client.erc20.transfers().min_amount(1000)
222
222
  assert query._params["min_amount"] == 1000
223
223
 
224
+ def test_max_amount_filter(self):
225
+ """max_amount should set param."""
226
+ client = DeFiStream(api_key="dsk_test")
227
+ query = client.erc20.transfers().max_amount(10000)
228
+ assert query._params["max_amount"] == 10000
229
+
224
230
  def test_start_time(self):
225
231
  """start_time should set since param."""
226
232
  client = DeFiStream(api_key="dsk_test")
@@ -240,7 +246,6 @@ class TestBuilderPattern:
240
246
  assert query._params["since"] == "2024-01-01"
241
247
  assert query._params["until"] == "2024-01-31"
242
248
 
243
-
244
249
  class TestAsyncBuilderPattern:
245
250
  """Test async builder pattern."""
246
251
 
@@ -269,12 +274,6 @@ class TestUniswapBuilder:
269
274
  assert query._params["symbol1"] == "USDC"
270
275
  assert query._params["fee"] == 500
271
276
 
272
- def test_pool_filter(self):
273
- """pool() should set pool param."""
274
- client = DeFiStream(api_key="dsk_test")
275
- query = client.uniswap.swaps().pool("0x123")
276
- assert query._params["pool"] == "0x123"
277
-
278
277
  def test_deposits_endpoint(self):
279
278
  """deposits() should use correct endpoint."""
280
279
  client = DeFiStream(api_key="dsk_test")
@@ -293,27 +292,17 @@ class TestUniswapBuilder:
293
292
  query = client.uniswap.collects("WETH", "USDC", 500)
294
293
  assert query._endpoint == "/uniswap/events/collect"
295
294
 
296
-
297
- class TestAAVEBuilder:
298
- """Test AAVE-specific builder methods."""
299
-
300
- def test_user_filter(self):
301
- """user() should set user param."""
295
+ def test_symbol_and_fee_chain_methods(self):
296
+ """symbol0, symbol1, fee should work as chain methods."""
302
297
  client = DeFiStream(api_key="dsk_test")
303
- query = client.aave.deposits().user("0x123")
304
- assert query._params["user"] == "0x123"
298
+ query = client.uniswap.swaps().symbol0("WETH").symbol1("USDC").fee(3000)
299
+ assert query._params["symbol0"] == "WETH"
300
+ assert query._params["symbol1"] == "USDC"
301
+ assert query._params["fee"] == 3000
305
302
 
306
- def test_reserve_filter(self):
307
- """reserve() should set reserve param."""
308
- client = DeFiStream(api_key="dsk_test")
309
- query = client.aave.deposits().reserve("0x456")
310
- assert query._params["reserve"] == "0x456"
311
303
 
312
- def test_liquidator_filter(self):
313
- """liquidator() should set liquidator param."""
314
- client = DeFiStream(api_key="dsk_test")
315
- query = client.aave.liquidations().liquidator("0x789")
316
- assert query._params["liquidator"] == "0x789"
304
+ class TestAAVEBuilder:
305
+ """Test AAVE-specific builder methods."""
317
306
 
318
307
  def test_flashloans_endpoint(self):
319
308
  """flashloans() should use correct endpoint."""
@@ -321,6 +310,12 @@ class TestAAVEBuilder:
321
310
  query = client.aave.flashloans()
322
311
  assert query._endpoint == "/aave/events/flashloan"
323
312
 
313
+ def test_eth_market_type_filter(self):
314
+ """eth_market_type should set param."""
315
+ client = DeFiStream(api_key="dsk_test")
316
+ query = client.aave.deposits().eth_market_type("Prime")
317
+ assert query._params["eth_market_type"] == "Prime"
318
+
324
319
 
325
320
  class TestQueryBuilderRepr:
326
321
  """Test QueryBuilder repr."""
File without changes
File without changes
File without changes
File without changes