blockapi 1.3.2__tar.gz → 1.4.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.
- {blockapi-1.3.2 → blockapi-1.4.0}/PKG-INFO +1 -1
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/nft/magic_eden.py +35 -6
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/nft/opensea.py +34 -7
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi.egg-info/PKG-INFO +1 -1
- {blockapi-1.3.2 → blockapi-1.4.0}/setup.py +1 -1
- {blockapi-1.3.2 → blockapi-1.4.0}/LICENSE.md +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/README.md +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/services.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/test_blockapi.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/test_num.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/test_random_user_agent.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/conftest.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/covalenth/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/covalenth/test_ethereum.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/fake_sleep_provider.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/nft/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/nft/test_magic_eden.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/nft/test_opensea.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/nft/test_simple_hash.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/nft/test_unisat.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/perpetual/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/perpetual/test_perpetual.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/synthetix/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/synthetix/test_synthetix.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_blockchainos.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_blockchair_btc.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_blockchair_doge.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_blockchair_ltc.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_cosmos.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_ethplorer.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_multisources.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_optimistic_etherscan.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_solana.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_subscan_polkadot.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_sui.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/api/test_trezor_btc.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/test_base.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/test_blockchain_api.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/test_blockchain_mapping.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/test_data.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/test_enumerate_classes.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/test_generic.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test/v2/test_models.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/test_data.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/utils/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/utils/address.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/utils/datetime.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/utils/num.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/utils/user_agent.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/blockchainos.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/blockchair.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/cosmos.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/arbitrum.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/astar.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/avalanche.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/axie.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/base.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/binance_smart_chain.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/ethereum.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/fantom.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/heco.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/iotex.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/klaytn.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/moonbeam.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/palm.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/polygon.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/covalenth/rsk.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/debank.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/debank_maps.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/ethplorer.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/nft/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/nft/simple_hash.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/nft/unisat.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/optimistic_etherscan.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/perpetual/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/perpetual/perp_abi.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/perpetual/perpetual.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/solana.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/subscan.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/sui.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/synthetix/__init__.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/synthetix/synthetix.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/synthetix/synthetix_abi.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/terra.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/trezor.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/api/web3_utils.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/base.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/blockchain_mapping.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/coin_mapping.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/coins.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi/v2/models.py +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi.egg-info/SOURCES.txt +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi.egg-info/dependency_links.txt +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi.egg-info/requires.txt +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/blockapi.egg-info/top_level.txt +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/pyproject.toml +0 -0
- {blockapi-1.3.2 → blockapi-1.4.0}/setup.cfg +0 -0
|
@@ -46,11 +46,21 @@ class MagicEdenApi(BlockchainApi, INftProvider, INftParser):
|
|
|
46
46
|
|
|
47
47
|
coin_map = NotImplemented
|
|
48
48
|
|
|
49
|
-
def __init__(self, sleep_provider):
|
|
49
|
+
def __init__(self, sleep_provider, max_listings=500, max_offers=500):
|
|
50
50
|
super().__init__()
|
|
51
|
-
|
|
52
51
|
self._sleep_provider = sleep_provider
|
|
53
52
|
|
|
53
|
+
self.max_offers = max_offers
|
|
54
|
+
if max_listings > 15000:
|
|
55
|
+
logger.warning(
|
|
56
|
+
'Listings cap exceeding 15000 will cause an error: '
|
|
57
|
+
'"offset should be non-negative integer". '
|
|
58
|
+
'Setting maximum to 15000.'
|
|
59
|
+
)
|
|
60
|
+
self.max_listings = 15000
|
|
61
|
+
else:
|
|
62
|
+
self.max_listings = max_listings
|
|
63
|
+
|
|
54
64
|
def fetch_nfts(self, address: str) -> FetchResult:
|
|
55
65
|
offset = 0
|
|
56
66
|
limit = 500
|
|
@@ -192,7 +202,12 @@ class MagicEdenApi(BlockchainApi, INftProvider, INftParser):
|
|
|
192
202
|
data_len = len(results)
|
|
193
203
|
offset += limit
|
|
194
204
|
|
|
195
|
-
if
|
|
205
|
+
if (
|
|
206
|
+
data.errors
|
|
207
|
+
or not data.data
|
|
208
|
+
or data_len < limit
|
|
209
|
+
or len(items) >= self.max_offers
|
|
210
|
+
):
|
|
196
211
|
return FetchResult(
|
|
197
212
|
status_code=data.status_code,
|
|
198
213
|
headers=data.headers,
|
|
@@ -257,7 +272,11 @@ class MagicEdenApi(BlockchainApi, INftProvider, INftParser):
|
|
|
257
272
|
return str(spot_price * (1 - seller_fee - takers_fee - lp_fee))
|
|
258
273
|
|
|
259
274
|
def fetch_listings(
|
|
260
|
-
self,
|
|
275
|
+
self,
|
|
276
|
+
collection: str,
|
|
277
|
+
cursor: Optional[str] = None,
|
|
278
|
+
sort="listPrice",
|
|
279
|
+
sort_direction="desc",
|
|
261
280
|
) -> FetchResult:
|
|
262
281
|
offset = 0
|
|
263
282
|
limit = 100
|
|
@@ -266,7 +285,12 @@ class MagicEdenApi(BlockchainApi, INftProvider, INftParser):
|
|
|
266
285
|
while True:
|
|
267
286
|
self._sleep_provider.sleep(self.base_url, self.api_options.rate_limit)
|
|
268
287
|
data = self.get_data(
|
|
269
|
-
'get_listings',
|
|
288
|
+
'get_listings',
|
|
289
|
+
slug=collection,
|
|
290
|
+
offset=offset,
|
|
291
|
+
limit=limit,
|
|
292
|
+
sort=sort,
|
|
293
|
+
sort_direction=sort_direction,
|
|
270
294
|
)
|
|
271
295
|
|
|
272
296
|
if self._should_retry(data):
|
|
@@ -277,7 +301,12 @@ class MagicEdenApi(BlockchainApi, INftProvider, INftParser):
|
|
|
277
301
|
offset += limit
|
|
278
302
|
|
|
279
303
|
# note: if offset is greater than 15000, causes response "offset should be non-negative integer"
|
|
280
|
-
if
|
|
304
|
+
if (
|
|
305
|
+
data.errors
|
|
306
|
+
or not data.data
|
|
307
|
+
or len(data.data) < limit
|
|
308
|
+
or len(items) > self.max_listings
|
|
309
|
+
):
|
|
281
310
|
return FetchResult(
|
|
282
311
|
status_code=data.status_code,
|
|
283
312
|
headers=data.headers,
|
|
@@ -3,7 +3,6 @@ import logging
|
|
|
3
3
|
from decimal import Decimal
|
|
4
4
|
from typing import Callable, Iterable, Optional, Tuple
|
|
5
5
|
|
|
6
|
-
from blockapi.utils.num import raw_to_decimals
|
|
7
6
|
from blockapi.v2.base import (
|
|
8
7
|
ApiException,
|
|
9
8
|
BlockchainApi,
|
|
@@ -98,6 +97,8 @@ class OpenSeaApi(BlockchainApi, INftProvider, INftParser):
|
|
|
98
97
|
blockchain: Blockchain,
|
|
99
98
|
sleep_provider: ISleepProvider = None,
|
|
100
99
|
limit: Optional[int] = None,
|
|
100
|
+
max_listings=500,
|
|
101
|
+
max_offers=500,
|
|
101
102
|
):
|
|
102
103
|
super().__init__(api_key)
|
|
103
104
|
|
|
@@ -110,6 +111,9 @@ class OpenSeaApi(BlockchainApi, INftProvider, INftParser):
|
|
|
110
111
|
self._sleep_provider = sleep_provider or SleepProvider()
|
|
111
112
|
self._limit = limit
|
|
112
113
|
|
|
114
|
+
self.max_listings = max_listings
|
|
115
|
+
self.max_offers = max_offers
|
|
116
|
+
|
|
113
117
|
def fetch_nfts(self, address: str, cursor: Optional[str] = None) -> FetchResult:
|
|
114
118
|
logger.info(f'Fetch nfts from {address}, cursor={cursor}')
|
|
115
119
|
return self._coalesce(self._yield_nfts(address, cursor))
|
|
@@ -256,17 +260,32 @@ class OpenSeaApi(BlockchainApi, INftProvider, INftParser):
|
|
|
256
260
|
self, fetch_method: Callable, key: str, cursor: Optional[str] = None
|
|
257
261
|
) -> Iterable[Tuple[FetchResult, Optional[str]]]:
|
|
258
262
|
cursors = set()
|
|
263
|
+
page_count = 0
|
|
264
|
+
item_count = 0
|
|
259
265
|
|
|
260
|
-
count = 0
|
|
261
266
|
while True:
|
|
262
267
|
self._sleep_provider.sleep(self.base_url, self.api_options.rate_limit)
|
|
263
|
-
|
|
264
|
-
logger.debug(f'Fetching page {
|
|
268
|
+
page_count += 1
|
|
269
|
+
logger.debug(f'Fetching page {page_count} of {key} from {cursor}')
|
|
265
270
|
fetched, next_cursor = fetch_method(key, cursor)
|
|
266
271
|
if self._should_retry(fetched):
|
|
267
|
-
|
|
272
|
+
page_count -= 1
|
|
268
273
|
continue
|
|
269
274
|
|
|
275
|
+
# Count items for dynamic limiting
|
|
276
|
+
item_limit = None
|
|
277
|
+
if fetched.data:
|
|
278
|
+
current_items = 0
|
|
279
|
+
if 'offers' in fetched.data:
|
|
280
|
+
current_items = len(fetched.data['offers'])
|
|
281
|
+
item_limit = self.max_offers
|
|
282
|
+
elif 'listings' in fetched.data:
|
|
283
|
+
current_items = len(fetched.data['listings'])
|
|
284
|
+
item_limit = self.max_listings
|
|
285
|
+
# skip `'nfts' in fetched.data`, because it doesn't have a limit
|
|
286
|
+
|
|
287
|
+
item_count += current_items
|
|
288
|
+
|
|
270
289
|
yield fetched, next_cursor
|
|
271
290
|
|
|
272
291
|
if not next_cursor:
|
|
@@ -278,13 +297,19 @@ class OpenSeaApi(BlockchainApi, INftProvider, INftParser):
|
|
|
278
297
|
|
|
279
298
|
cursors.add(cursor)
|
|
280
299
|
|
|
281
|
-
|
|
300
|
+
# Check both page and item limits
|
|
301
|
+
if self._limit and page_count >= self._limit:
|
|
302
|
+
break
|
|
303
|
+
|
|
304
|
+
if item_limit and item_count >= item_limit:
|
|
282
305
|
break
|
|
283
306
|
|
|
284
307
|
def _fetch_offers_page(
|
|
285
308
|
self, method: str, collection: str, cursor: Optional[str] = None
|
|
286
309
|
) -> tuple[FetchResult, Optional[str]]:
|
|
287
|
-
params =
|
|
310
|
+
params = {'limit': 100} # the max limit allowed is 100 items per page
|
|
311
|
+
if cursor:
|
|
312
|
+
params['next'] = cursor
|
|
288
313
|
|
|
289
314
|
fetched = self.get_data(
|
|
290
315
|
method,
|
|
@@ -573,9 +598,11 @@ class OpenSeaApi(BlockchainApi, INftProvider, INftParser):
|
|
|
573
598
|
errors = []
|
|
574
599
|
last = None
|
|
575
600
|
last_cursor = None
|
|
601
|
+
|
|
576
602
|
for item, cursor in fetch_results:
|
|
577
603
|
last_cursor = cursor
|
|
578
604
|
last = item
|
|
605
|
+
|
|
579
606
|
if item.data:
|
|
580
607
|
data.append(item.data)
|
|
581
608
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|