blockapi 1.2.0__tar.gz → 1.3.1__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.2.0 → blockapi-1.3.1}/PKG-INFO +27 -5
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/__init__.py +0 -25
- blockapi-1.3.1/blockapi/test/v2/api/test_subscan_polkadot.py +92 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/test_enumerate_classes.py +0 -2
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/subscan.py +12 -36
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi.egg-info/PKG-INFO +27 -5
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi.egg-info/SOURCES.txt +0 -56
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi.egg-info/requires.txt +1 -1
- {blockapi-1.2.0 → blockapi-1.3.1}/setup.py +2 -2
- blockapi-1.2.0/blockapi/api/__init__.py +0 -32
- blockapi-1.2.0/blockapi/api/alethio.py +0 -372
- blockapi-1.2.0/blockapi/api/amberdata.py +0 -152
- blockapi-1.2.0/blockapi/api/binance.py +0 -75
- blockapi-1.2.0/blockapi/api/blockchaininfo.py +0 -81
- blockapi-1.2.0/blockapi/api/blockchainos.py +0 -92
- blockapi-1.2.0/blockapi/api/blockchair.py +0 -196
- blockapi-1.2.0/blockapi/api/blockcypher.py +0 -45
- blockapi-1.2.0/blockapi/api/blockonomics.py +0 -76
- blockapi-1.2.0/blockapi/api/blockscout.py +0 -104
- blockapi-1.2.0/blockapi/api/btc.py +0 -35
- blockapi-1.2.0/blockapi/api/cardanoexplorer.py +0 -84
- blockapi-1.2.0/blockapi/api/chainso.py +0 -94
- blockapi-1.2.0/blockapi/api/cosmos.py +0 -339
- blockapi-1.2.0/blockapi/api/cryptoid.py +0 -51
- blockapi-1.2.0/blockapi/api/dcrdata.py +0 -227
- blockapi-1.2.0/blockapi/api/digonchain.py +0 -40
- blockapi-1.2.0/blockapi/api/eospark.py +0 -57
- blockapi-1.2.0/blockapi/api/etherscan.py +0 -144
- blockapi-1.2.0/blockapi/api/ethplorer.py +0 -67
- blockapi-1.2.0/blockapi/api/greymass.py +0 -45
- blockapi-1.2.0/blockapi/api/insight.py +0 -84
- blockapi-1.2.0/blockapi/api/kyber.py +0 -175
- blockapi-1.2.0/blockapi/api/neoscan.py +0 -107
- blockapi-1.2.0/blockapi/api/ontology.py +0 -35
- blockapi-1.2.0/blockapi/api/solana.py +0 -155
- blockapi-1.2.0/blockapi/api/stellar.py +0 -41
- blockapi-1.2.0/blockapi/api/subscan.py +0 -284
- blockapi-1.2.0/blockapi/api/terra_money.py +0 -138
- blockapi-1.2.0/blockapi/api/trezor.py +0 -87
- blockapi-1.2.0/blockapi/api/tronscan.py +0 -75
- blockapi-1.2.0/blockapi/api/tzscan.py +0 -312
- blockapi-1.2.0/blockapi/api/tzstats.py +0 -29
- blockapi-1.2.0/blockapi/api/zchain.py +0 -31
- blockapi-1.2.0/blockapi/api/zensystem.py +0 -31
- blockapi-1.2.0/blockapi/test/api/test_amberdata.py +0 -29
- blockapi-1.2.0/blockapi/test/api/test_balances.py +0 -28
- blockapi-1.2.0/blockapi/test/api/test_binance.py +0 -28
- blockapi-1.2.0/blockapi/test/api/test_blockchainos.py +0 -23
- blockapi-1.2.0/blockapi/test/api/test_blockchair.py +0 -23
- blockapi-1.2.0/blockapi/test/api/test_blockscout.py +0 -26
- blockapi-1.2.0/blockapi/test/api/test_btc.py +0 -15
- blockapi-1.2.0/blockapi/test/api/test_cosmos.py +0 -68
- blockapi-1.2.0/blockapi/test/api/test_dcrdata.py +0 -78
- blockapi-1.2.0/blockapi/test/api/test_digonchain.py +0 -15
- blockapi-1.2.0/blockapi/test/api/test_insight.py +0 -15
- blockapi-1.2.0/blockapi/test/api/test_kyber.py +0 -88
- blockapi-1.2.0/blockapi/test/api/test_ontio.py +0 -13
- blockapi-1.2.0/blockapi/test/api/test_solana.py +0 -38
- blockapi-1.2.0/blockapi/test/api/test_subscan.py +0 -41
- blockapi-1.2.0/blockapi/test/api/test_terra_money.py +0 -41
- blockapi-1.2.0/blockapi/test/api/test_tronscan.py +0 -16
- blockapi-1.2.0/blockapi/test/api/test_tzscan.py +0 -44
- blockapi-1.2.0/blockapi/test/api/test_tzstats.py +0 -31
- blockapi-1.2.0/blockapi/test/v2/api/test_subscan_polkadot.py +0 -32
- blockapi-1.2.0/blockapi/utils/__init__.py +0 -1
- blockapi-1.2.0/blockapi/utils/ethereum.py +0 -259
- {blockapi-1.2.0 → blockapi-1.3.1}/LICENSE.md +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/README.md +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/services.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/test_blockapi.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/test_num.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/test_random_user_agent.py +0 -0
- {blockapi-1.2.0/blockapi/test/api → blockapi-1.3.1/blockapi/test/v2}/__init__.py +0 -0
- {blockapi-1.2.0/blockapi/test/v2 → blockapi-1.3.1/blockapi/test/v2/api}/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/conftest.py +0 -0
- {blockapi-1.2.0/blockapi/test/v2/api → blockapi-1.3.1/blockapi/test/v2/api/covalenth}/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/covalenth/test_ethereum.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/fake_sleep_provider.py +0 -0
- {blockapi-1.2.0/blockapi/test/v2/api/covalenth → blockapi-1.3.1/blockapi/test/v2/api/nft}/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/nft/test_magic_eden.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/nft/test_opensea.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/nft/test_simple_hash.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/nft/test_unisat.py +0 -0
- {blockapi-1.2.0/blockapi/test/v2/api/nft → blockapi-1.3.1/blockapi/test/v2/api/perpetual}/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/perpetual/test_perpetual.py +0 -0
- {blockapi-1.2.0/blockapi/test/v2/api/perpetual → blockapi-1.3.1/blockapi/test/v2/api/synthetix}/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/synthetix/test_synthetix.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/test_blockchainos.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/test_blockchair_btc.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/test_blockchair_doge.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/test_blockchair_ltc.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/test_cosmos.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/test_ethplorer.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/test_multisources.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/test_optimistic_etherscan.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/test_solana.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/test_sui.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/api/test_trezor_btc.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/test_base.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/test_blockchain_api.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/test_blockchain_mapping.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/test_data.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/test_generic.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test/v2/test_models.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/test_data.py +0 -0
- {blockapi-1.2.0/blockapi/test/v2/api/synthetix → blockapi-1.3.1/blockapi/utils}/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/utils/address.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/utils/datetime.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/utils/num.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/utils/user_agent.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/blockchainos.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/blockchair.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/cosmos.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/arbitrum.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/astar.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/avalanche.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/axie.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/base.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/binance_smart_chain.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/ethereum.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/fantom.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/heco.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/iotex.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/klaytn.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/moonbeam.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/palm.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/polygon.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/covalenth/rsk.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/debank.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/debank_maps.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/ethplorer.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/nft/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/nft/magic_eden.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/nft/opensea.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/nft/simple_hash.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/nft/unisat.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/optimistic_etherscan.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/perpetual/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/perpetual/perp_abi.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/perpetual/perpetual.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/solana.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/sui.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/synthetix/__init__.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/synthetix/synthetix.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/synthetix/synthetix_abi.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/terra.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/trezor.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/api/web3_utils.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/base.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/blockchain_mapping.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/coin_mapping.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/coins.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi/v2/models.py +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi.egg-info/dependency_links.txt +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/blockapi.egg-info/top_level.txt +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/pyproject.toml +0 -0
- {blockapi-1.2.0 → blockapi-1.3.1}/setup.cfg +0 -0
|
@@ -1,13 +1,37 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: blockapi
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.1
|
|
4
4
|
Summary: BlockAPI library
|
|
5
5
|
Home-page: https://github.com/crypkit/blockapi
|
|
6
6
|
Author: Devmons s.r.o.
|
|
7
7
|
License: MIT
|
|
8
|
-
Platform: UNKNOWN
|
|
9
8
|
Description-Content-Type: text/markdown
|
|
10
9
|
License-File: LICENSE.md
|
|
10
|
+
Requires-Dist: requests==2.32.4
|
|
11
|
+
Requires-Dist: pytz>=2019.2
|
|
12
|
+
Requires-Dist: python-dateutil>=2.8.0
|
|
13
|
+
Requires-Dist: coinaddrng==1.1.1
|
|
14
|
+
Requires-Dist: cfscrape>=2.0.8
|
|
15
|
+
Requires-Dist: ethereum_input_decoder>=0.2.2
|
|
16
|
+
Requires-Dist: web3<6.0.0,>=5.2.2
|
|
17
|
+
Requires-Dist: bs4>=0.0.1
|
|
18
|
+
Requires-Dist: lxml>=4.4.1
|
|
19
|
+
Requires-Dist: pydantic>=1.10.2
|
|
20
|
+
Requires-Dist: marko==1.3.0
|
|
21
|
+
Requires-Dist: fake_useragent>=1.1.3
|
|
22
|
+
Requires-Dist: pytest
|
|
23
|
+
Requires-Dist: pytest-vcr
|
|
24
|
+
Requires-Dist: requests_mock>=1.9.3
|
|
25
|
+
Requires-Dist: attrs<=22.1.0,>=17.4.0
|
|
26
|
+
Requires-Dist: solders==0.22.0
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: description-content-type
|
|
30
|
+
Dynamic: home-page
|
|
31
|
+
Dynamic: license
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
Dynamic: requires-dist
|
|
34
|
+
Dynamic: summary
|
|
11
35
|
|
|
12
36
|
# blockapi
|
|
13
37
|
|
|
@@ -157,5 +181,3 @@ See also the list of [contributors](https://github.com/crypkit/blockapi/contribu
|
|
|
157
181
|
|
|
158
182
|
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
|
|
159
183
|
|
|
160
|
-
|
|
161
|
-
|
|
@@ -3,7 +3,6 @@ import random
|
|
|
3
3
|
|
|
4
4
|
import coinaddrng
|
|
5
5
|
|
|
6
|
-
import blockapi.api
|
|
7
6
|
import blockapi.utils
|
|
8
7
|
|
|
9
8
|
from .services import APIError
|
|
@@ -111,30 +110,6 @@ def _inheritors(klass):
|
|
|
111
110
|
return subclasses
|
|
112
111
|
|
|
113
112
|
|
|
114
|
-
def _get_subclasses(class_name):
|
|
115
|
-
return [getattr(class_name, x) for x in dir(class_name) if not x.startswith('__')]
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def _get_all_inheritors():
|
|
119
|
-
all_inheritors = []
|
|
120
|
-
|
|
121
|
-
tridy = _get_subclasses(blockapi.api)
|
|
122
|
-
|
|
123
|
-
for trida in tridy:
|
|
124
|
-
tridy_sub = _get_subclasses(trida)
|
|
125
|
-
for trida_sub in tridy_sub:
|
|
126
|
-
if (
|
|
127
|
-
inspect.isclass(trida_sub)
|
|
128
|
-
and blockapi.services.BlockchainAPI in trida_sub.__bases__
|
|
129
|
-
):
|
|
130
|
-
all_inheritors.append(trida_sub)
|
|
131
|
-
grandchildren = _inheritors(trida_sub)
|
|
132
|
-
if len(grandchildren) > 0:
|
|
133
|
-
all_inheritors += _inheritors(trida_sub)
|
|
134
|
-
|
|
135
|
-
return all_inheritors
|
|
136
|
-
|
|
137
|
-
|
|
138
113
|
def get_working_apis_for_coin(symbol, debug=False):
|
|
139
114
|
coin_classes = get_api_classes_for_coin(symbol)
|
|
140
115
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from blockapi.test.v2.api.conftest import read_file
|
|
6
|
+
from blockapi.v2.api import PolkadotSubscanApi
|
|
7
|
+
from blockapi.v2.models import AssetType
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.fixture
|
|
11
|
+
def api():
|
|
12
|
+
"""Create a PolkadotSubscanApi instance for testing."""
|
|
13
|
+
return PolkadotSubscanApi()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.mark.parametrize(
|
|
17
|
+
'address, response_path, expected_balance',
|
|
18
|
+
[
|
|
19
|
+
(
|
|
20
|
+
'1NjjK81oA9is7eWhFJ7n7kQhaPT3pnxLFH5MkwDfduAiWE9',
|
|
21
|
+
'data/subscan_polkadot_response_WE9.json',
|
|
22
|
+
Decimal('4649.9139999889'),
|
|
23
|
+
),
|
|
24
|
+
(
|
|
25
|
+
'15j4dg5GzsL1bw2U2AWgeyAk6QTxq43V7ZPbXdAmbVLjvDCK',
|
|
26
|
+
'data/subscan_polkadot_response_DCK.json',
|
|
27
|
+
Decimal('17970279.0085871699'),
|
|
28
|
+
),
|
|
29
|
+
],
|
|
30
|
+
)
|
|
31
|
+
def test_fetch_balances(requests_mock, address, response_path, expected_balance, api):
|
|
32
|
+
requests_mock.post(
|
|
33
|
+
'https://polkadot.api.subscan.io/api/v2/scan/search',
|
|
34
|
+
text=read_file(response_path),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
balances = api.get_balance(address)
|
|
38
|
+
assert sum(b.balance for b in balances) == expected_balance
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_real_problematic_address_overlap(requests_mock, api):
|
|
42
|
+
"""
|
|
43
|
+
Test the real problematic address that exhibits balance overlap.
|
|
44
|
+
"""
|
|
45
|
+
requests_mock.post(
|
|
46
|
+
'https://polkadot.api.subscan.io/api/v2/scan/search',
|
|
47
|
+
text=read_file('data/subscan_polkadot_balance_overlap_1567z.json'),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
balances = list(api.get_balance("1567zYrTN6G1YXoF47KyC5Lyto8MhJjzDB8dY8ZvudMAAEet"))
|
|
51
|
+
available_balances = [b for b in balances if b.asset_type == AssetType.AVAILABLE]
|
|
52
|
+
|
|
53
|
+
assert len(available_balances) == 1, "Expected 1 available balance item"
|
|
54
|
+
available_balance = available_balances[0]
|
|
55
|
+
|
|
56
|
+
# Correct calculation: 69.1806120067 - 64.5655723106 = 4.6150396961 DOT
|
|
57
|
+
expected_balance = Decimal("4.6150396961")
|
|
58
|
+
assert (
|
|
59
|
+
available_balance.balance == expected_balance
|
|
60
|
+
), f"Expected {expected_balance}, got {available_balance.balance}"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_second_problematic_address_overlap(requests_mock, api):
|
|
64
|
+
"""
|
|
65
|
+
Test another problematic address with reserved > locked scenario.
|
|
66
|
+
|
|
67
|
+
Address 15gT3MY2oVDqi1WPFnpkhPKVNUXAUPscMagaJeW8dqmLzfJ6 has large reserved
|
|
68
|
+
amount (154.31 DOT) but no staking locks, demonstrating reserved > locked case.
|
|
69
|
+
"""
|
|
70
|
+
requests_mock.post(
|
|
71
|
+
'https://polkadot.api.subscan.io/api/v2/scan/search',
|
|
72
|
+
text=read_file('data/subscan_polkadot_balance_overlap_15gT3.json'),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
balances = list(api.get_balance("15gT3MY2oVDqi1WPFnpkhPKVNUXAUPscMagaJeW8dqmLzfJ6"))
|
|
76
|
+
|
|
77
|
+
available_balances = [b for b in balances if b.asset_type == AssetType.AVAILABLE]
|
|
78
|
+
assert len(available_balances) == 1
|
|
79
|
+
available_balance = available_balances[0]
|
|
80
|
+
|
|
81
|
+
# 162.469 total, 154.307 locked
|
|
82
|
+
expected_balance = Decimal('8.1611794137')
|
|
83
|
+
assert (
|
|
84
|
+
available_balance.balance == expected_balance
|
|
85
|
+
), f"Expected {expected_balance}, got {available_balance.balance}"
|
|
86
|
+
|
|
87
|
+
other_balances = [b for b in balances if b.asset_type != AssetType.AVAILABLE]
|
|
88
|
+
assert len(other_balances) == 1
|
|
89
|
+
|
|
90
|
+
other_balance = other_balances[0]
|
|
91
|
+
assert other_balance.balance == Decimal('154.3078601187')
|
|
92
|
+
assert other_balance.asset_type == AssetType.LOCKED
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
2
|
|
|
3
|
-
from blockapi.api import SolanaApi
|
|
4
3
|
from blockapi.test.v2.test_data import (
|
|
5
4
|
get_debank_addresses,
|
|
6
5
|
yield_api_balance_classes,
|
|
@@ -28,7 +27,6 @@ def test_enumerate_subclasses():
|
|
|
28
27
|
classes = [x.__name__ for x in yield_api_balance_classes()]
|
|
29
28
|
|
|
30
29
|
assert classes
|
|
31
|
-
assert SolanaApi.__name__ in classes
|
|
32
30
|
assert EthplorerApi.__name__ in classes
|
|
33
31
|
assert DebankApi.__name__ not in classes
|
|
34
32
|
assert PerpetualApi.__name__ not in classes
|
|
@@ -43,7 +43,7 @@ class SubscanApi(BlockchainApi, BalanceMixin, ABC):
|
|
|
43
43
|
return FetchResult(data=response)
|
|
44
44
|
|
|
45
45
|
def parse_balances(self, fetch_result: FetchResult) -> ParseResult:
|
|
46
|
-
balances = list(self.
|
|
46
|
+
balances = list(self._yield_native_balances_zero_zum(fetch_result.data))
|
|
47
47
|
|
|
48
48
|
# add staking rewards (and slashes) too? it's a lot of requests
|
|
49
49
|
# per single address
|
|
@@ -52,34 +52,15 @@ class SubscanApi(BlockchainApi, BalanceMixin, ABC):
|
|
|
52
52
|
|
|
53
53
|
return ParseResult(data=balances)
|
|
54
54
|
|
|
55
|
-
def
|
|
55
|
+
def _yield_native_balances_zero_zum(self, response: dict) -> Iterable[BalanceItem]:
|
|
56
56
|
data = response['data']['account']
|
|
57
57
|
b_total = decimals_to_raw(data['balance'], self.coin.decimals)
|
|
58
58
|
if b_total == 0:
|
|
59
59
|
return []
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
b_staked = Decimal(0)
|
|
64
|
-
if data['staking_info']:
|
|
65
|
-
b_staked = b_total_locked
|
|
66
|
-
|
|
67
|
-
# ignore data['unbonding'] - it's still staked
|
|
68
|
-
|
|
69
|
-
b_reserved = safe_opt_decimal(data['reserved'])
|
|
70
|
-
b_vesting = (
|
|
71
|
-
to_decimal(data['vesting']['total_locked'])
|
|
72
|
-
if data['vesting']
|
|
73
|
-
else Decimal(0)
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
# do we want to include these?
|
|
77
|
-
# b_democracy = safe_opt_decimal(data['democracy_lock'])
|
|
78
|
-
# b_election = safe_opt_decimal(data['election_lock'])
|
|
79
|
-
|
|
80
|
-
b_available = b_total - b_total_locked - b_reserved
|
|
81
|
-
b_locked = b_reserved
|
|
61
|
+
b_reserved = safe_opt_decimal(data.get('reserved'))
|
|
82
62
|
|
|
63
|
+
b_available = b_total - b_reserved
|
|
83
64
|
if b_available:
|
|
84
65
|
yield BalanceItem.from_api(
|
|
85
66
|
balance_raw=int(b_available),
|
|
@@ -88,25 +69,20 @@ class SubscanApi(BlockchainApi, BalanceMixin, ABC):
|
|
|
88
69
|
raw=data,
|
|
89
70
|
)
|
|
90
71
|
|
|
91
|
-
|
|
72
|
+
b_bonded = safe_opt_decimal(data.get('bonded'))
|
|
73
|
+
if b_bonded:
|
|
92
74
|
yield BalanceItem.from_api(
|
|
93
|
-
balance_raw=int(
|
|
75
|
+
balance_raw=int(b_bonded),
|
|
94
76
|
coin=self.coin,
|
|
95
77
|
asset_type=AssetType.STAKED,
|
|
96
|
-
raw=data,
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
if b_vesting:
|
|
100
|
-
yield BalanceItem.from_api(
|
|
101
|
-
balance_raw=int(b_vesting),
|
|
102
|
-
coin=self.coin,
|
|
103
|
-
asset_type=AssetType.VESTING,
|
|
104
|
-
raw=data['vesting'],
|
|
78
|
+
raw=data['bonded'],
|
|
105
79
|
)
|
|
106
80
|
|
|
107
|
-
|
|
81
|
+
# Others: reserved - bonded (includes unbonding + other reserves)
|
|
82
|
+
b_others = b_reserved - b_bonded
|
|
83
|
+
if b_others > 0:
|
|
108
84
|
yield BalanceItem.from_api(
|
|
109
|
-
balance_raw=int(
|
|
85
|
+
balance_raw=int(b_others),
|
|
110
86
|
coin=self.coin,
|
|
111
87
|
asset_type=AssetType.LOCKED,
|
|
112
88
|
raw=data,
|
|
@@ -1,13 +1,37 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: blockapi
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.1
|
|
4
4
|
Summary: BlockAPI library
|
|
5
5
|
Home-page: https://github.com/crypkit/blockapi
|
|
6
6
|
Author: Devmons s.r.o.
|
|
7
7
|
License: MIT
|
|
8
|
-
Platform: UNKNOWN
|
|
9
8
|
Description-Content-Type: text/markdown
|
|
10
9
|
License-File: LICENSE.md
|
|
10
|
+
Requires-Dist: requests==2.32.4
|
|
11
|
+
Requires-Dist: pytz>=2019.2
|
|
12
|
+
Requires-Dist: python-dateutil>=2.8.0
|
|
13
|
+
Requires-Dist: coinaddrng==1.1.1
|
|
14
|
+
Requires-Dist: cfscrape>=2.0.8
|
|
15
|
+
Requires-Dist: ethereum_input_decoder>=0.2.2
|
|
16
|
+
Requires-Dist: web3<6.0.0,>=5.2.2
|
|
17
|
+
Requires-Dist: bs4>=0.0.1
|
|
18
|
+
Requires-Dist: lxml>=4.4.1
|
|
19
|
+
Requires-Dist: pydantic>=1.10.2
|
|
20
|
+
Requires-Dist: marko==1.3.0
|
|
21
|
+
Requires-Dist: fake_useragent>=1.1.3
|
|
22
|
+
Requires-Dist: pytest
|
|
23
|
+
Requires-Dist: pytest-vcr
|
|
24
|
+
Requires-Dist: requests_mock>=1.9.3
|
|
25
|
+
Requires-Dist: attrs<=22.1.0,>=17.4.0
|
|
26
|
+
Requires-Dist: solders==0.22.0
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: description-content-type
|
|
30
|
+
Dynamic: home-page
|
|
31
|
+
Dynamic: license
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
Dynamic: requires-dist
|
|
34
|
+
Dynamic: summary
|
|
11
35
|
|
|
12
36
|
# blockapi
|
|
13
37
|
|
|
@@ -157,5 +181,3 @@ See also the list of [contributors](https://github.com/crypkit/blockapi/contribu
|
|
|
157
181
|
|
|
158
182
|
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
|
|
159
183
|
|
|
160
|
-
|
|
161
|
-
|
|
@@ -11,65 +11,10 @@ blockapi.egg-info/SOURCES.txt
|
|
|
11
11
|
blockapi.egg-info/dependency_links.txt
|
|
12
12
|
blockapi.egg-info/requires.txt
|
|
13
13
|
blockapi.egg-info/top_level.txt
|
|
14
|
-
blockapi/api/__init__.py
|
|
15
|
-
blockapi/api/alethio.py
|
|
16
|
-
blockapi/api/amberdata.py
|
|
17
|
-
blockapi/api/binance.py
|
|
18
|
-
blockapi/api/blockchaininfo.py
|
|
19
|
-
blockapi/api/blockchainos.py
|
|
20
|
-
blockapi/api/blockchair.py
|
|
21
|
-
blockapi/api/blockcypher.py
|
|
22
|
-
blockapi/api/blockonomics.py
|
|
23
|
-
blockapi/api/blockscout.py
|
|
24
|
-
blockapi/api/btc.py
|
|
25
|
-
blockapi/api/cardanoexplorer.py
|
|
26
|
-
blockapi/api/chainso.py
|
|
27
|
-
blockapi/api/cosmos.py
|
|
28
|
-
blockapi/api/cryptoid.py
|
|
29
|
-
blockapi/api/dcrdata.py
|
|
30
|
-
blockapi/api/digonchain.py
|
|
31
|
-
blockapi/api/eospark.py
|
|
32
|
-
blockapi/api/etherscan.py
|
|
33
|
-
blockapi/api/ethplorer.py
|
|
34
|
-
blockapi/api/greymass.py
|
|
35
|
-
blockapi/api/insight.py
|
|
36
|
-
blockapi/api/kyber.py
|
|
37
|
-
blockapi/api/neoscan.py
|
|
38
|
-
blockapi/api/ontology.py
|
|
39
|
-
blockapi/api/solana.py
|
|
40
|
-
blockapi/api/stellar.py
|
|
41
|
-
blockapi/api/subscan.py
|
|
42
|
-
blockapi/api/terra_money.py
|
|
43
|
-
blockapi/api/trezor.py
|
|
44
|
-
blockapi/api/tronscan.py
|
|
45
|
-
blockapi/api/tzscan.py
|
|
46
|
-
blockapi/api/tzstats.py
|
|
47
|
-
blockapi/api/zchain.py
|
|
48
|
-
blockapi/api/zensystem.py
|
|
49
14
|
blockapi/test/__init__.py
|
|
50
15
|
blockapi/test/test_blockapi.py
|
|
51
16
|
blockapi/test/test_num.py
|
|
52
17
|
blockapi/test/test_random_user_agent.py
|
|
53
|
-
blockapi/test/api/__init__.py
|
|
54
|
-
blockapi/test/api/test_amberdata.py
|
|
55
|
-
blockapi/test/api/test_balances.py
|
|
56
|
-
blockapi/test/api/test_binance.py
|
|
57
|
-
blockapi/test/api/test_blockchainos.py
|
|
58
|
-
blockapi/test/api/test_blockchair.py
|
|
59
|
-
blockapi/test/api/test_blockscout.py
|
|
60
|
-
blockapi/test/api/test_btc.py
|
|
61
|
-
blockapi/test/api/test_cosmos.py
|
|
62
|
-
blockapi/test/api/test_dcrdata.py
|
|
63
|
-
blockapi/test/api/test_digonchain.py
|
|
64
|
-
blockapi/test/api/test_insight.py
|
|
65
|
-
blockapi/test/api/test_kyber.py
|
|
66
|
-
blockapi/test/api/test_ontio.py
|
|
67
|
-
blockapi/test/api/test_solana.py
|
|
68
|
-
blockapi/test/api/test_subscan.py
|
|
69
|
-
blockapi/test/api/test_terra_money.py
|
|
70
|
-
blockapi/test/api/test_tronscan.py
|
|
71
|
-
blockapi/test/api/test_tzscan.py
|
|
72
|
-
blockapi/test/api/test_tzstats.py
|
|
73
18
|
blockapi/test/v2/__init__.py
|
|
74
19
|
blockapi/test/v2/test_base.py
|
|
75
20
|
blockapi/test/v2/test_blockchain_api.py
|
|
@@ -107,7 +52,6 @@ blockapi/test/v2/api/synthetix/test_synthetix.py
|
|
|
107
52
|
blockapi/utils/__init__.py
|
|
108
53
|
blockapi/utils/address.py
|
|
109
54
|
blockapi/utils/datetime.py
|
|
110
|
-
blockapi/utils/ethereum.py
|
|
111
55
|
blockapi/utils/num.py
|
|
112
56
|
blockapi/utils/user_agent.py
|
|
113
57
|
blockapi/v2/__init__.py
|
|
@@ -6,7 +6,7 @@ with open("README.md", "r") as f:
|
|
|
6
6
|
|
|
7
7
|
PACKAGES = find_packages(where='.')
|
|
8
8
|
|
|
9
|
-
__version__ = "1.
|
|
9
|
+
__version__ = "1.3.1"
|
|
10
10
|
|
|
11
11
|
setuptools.setup(
|
|
12
12
|
name='blockapi',
|
|
@@ -18,7 +18,7 @@ setuptools.setup(
|
|
|
18
18
|
long_description_content_type='text/markdown',
|
|
19
19
|
packages=PACKAGES,
|
|
20
20
|
install_requires=[
|
|
21
|
-
'requests==2.32.
|
|
21
|
+
'requests==2.32.4',
|
|
22
22
|
'pytz>=2019.2',
|
|
23
23
|
'python-dateutil>=2.8.0',
|
|
24
24
|
'coinaddrng==1.1.1',
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
from blockapi.api.alethio import *
|
|
2
|
-
from blockapi.api.amberdata import *
|
|
3
|
-
from blockapi.api.binance import *
|
|
4
|
-
from blockapi.api.blockchaininfo import *
|
|
5
|
-
from blockapi.api.blockchainos import *
|
|
6
|
-
from blockapi.api.blockchair import *
|
|
7
|
-
from blockapi.api.blockcypher import *
|
|
8
|
-
from blockapi.api.blockonomics import *
|
|
9
|
-
from blockapi.api.blockscout import *
|
|
10
|
-
from blockapi.api.btc import *
|
|
11
|
-
from blockapi.api.cardanoexplorer import *
|
|
12
|
-
from blockapi.api.chainso import *
|
|
13
|
-
from blockapi.api.cosmos import *
|
|
14
|
-
from blockapi.api.cryptoid import *
|
|
15
|
-
from blockapi.api.dcrdata import *
|
|
16
|
-
from blockapi.api.digonchain import *
|
|
17
|
-
from blockapi.api.eospark import *
|
|
18
|
-
from blockapi.api.etherscan import *
|
|
19
|
-
from blockapi.api.ethplorer import *
|
|
20
|
-
from blockapi.api.greymass import *
|
|
21
|
-
from blockapi.api.insight import *
|
|
22
|
-
from blockapi.api.neoscan import *
|
|
23
|
-
from blockapi.api.ontology import *
|
|
24
|
-
from blockapi.api.solana import *
|
|
25
|
-
from blockapi.api.stellar import *
|
|
26
|
-
from blockapi.api.terra_money import *
|
|
27
|
-
from blockapi.api.trezor import *
|
|
28
|
-
from blockapi.api.tronscan import *
|
|
29
|
-
from blockapi.api.tzscan import *
|
|
30
|
-
from blockapi.api.tzstats import *
|
|
31
|
-
from blockapi.api.zchain import *
|
|
32
|
-
from blockapi.api.zensystem import *
|