blockapi 2.5.6__tar.gz → 2.6.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-2.5.6 → blockapi-2.6.0}/PKG-INFO +1 -1
- blockapi-2.6.0/blockapi/test/v2/api/test_bitaps_ltc.py +39 -0
- blockapi-2.6.0/blockapi/test/v2/api/test_litecoinspace.py +46 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/__init__.py +2 -0
- blockapi-2.6.0/blockapi/v2/api/bitaps.py +53 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/debank.py +11 -0
- blockapi-2.6.0/blockapi/v2/api/litecoinspace.py +55 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/models.py +32 -1
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi.egg-info/PKG-INFO +1 -1
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi.egg-info/SOURCES.txt +4 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/setup.py +1 -1
- {blockapi-2.5.6 → blockapi-2.6.0}/LICENSE.md +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/README.md +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/services.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/test_blockapi.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/test_num.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/test_random_user_agent.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/conftest.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/covalenth/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/covalenth/test_ethereum.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/fake_sleep_provider.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/nft/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/nft/test_magic_eden.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/nft/test_opensea.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/nft/test_simple_hash.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/nft/test_unisat.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/perpetual/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/perpetual/test_perpetual.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/synthetix/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/synthetix/test_synthetix.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_blockchain_info.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_blockchainos.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_blockchair_btc.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_blockchair_doge.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_blockchair_ltc.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_cosmos.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_ethplorer.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_haskoin.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_multisources.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_optimistic_etherscan.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_solana.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_subscan_polkadot.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_sui.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_terra.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_trezor_btc.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/api/test_trezor_zec.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/test_base.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/test_blockchain_api.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/test_blockchain_mapping.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/test_data.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/test_enumerate_classes.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/test_generic.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test/v2/test_models.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/test_data.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/utils/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/utils/address.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/utils/datetime.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/utils/num.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/utils/user_agent.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/blockchain_info.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/blockchainos.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/blockchair.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/cosmos.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/arbitrum.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/astar.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/avalanche.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/axie.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/base.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/binance_smart_chain.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/ethereum.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/fantom.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/heco.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/iotex.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/klaytn.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/moonbeam.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/palm.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/polygon.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/covalenth/rsk.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/debank_maps.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/ethplorer.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/haskoin.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/nft/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/nft/magic_eden.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/nft/opensea.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/nft/simple_hash.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/nft/unisat.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/optimistic_etherscan.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/perpetual/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/perpetual/perp_abi.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/perpetual/perpetual.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/solana.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/subscan.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/sui.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/synthetix/__init__.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/synthetix/synthetix.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/synthetix/synthetix_abi.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/terra.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/trezor.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/api/web3_utils.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/base.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/blockchain_mapping.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/coin_mapping.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi/v2/coins.py +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi.egg-info/dependency_links.txt +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi.egg-info/requires.txt +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/blockapi.egg-info/top_level.txt +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/pyproject.toml +0 -0
- {blockapi-2.5.6 → blockapi-2.6.0}/setup.cfg +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from blockapi.test.v2.api.conftest import read_file
|
|
6
|
+
from blockapi.test.v2.test_data import ltc_test_address
|
|
7
|
+
from blockapi.v2.api.bitaps import BitapsLitecoinApi
|
|
8
|
+
from blockapi.v2.models import FetchResult
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_fetch_balances(requests_mock, bitaps_ltc_balance_response):
|
|
12
|
+
requests_mock.get(
|
|
13
|
+
f'https://api.bitaps.com/ltc/v1/blockchain/address/state/{ltc_test_address}',
|
|
14
|
+
text=bitaps_ltc_balance_response,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
api = BitapsLitecoinApi()
|
|
18
|
+
balances = api.get_balance(ltc_test_address)
|
|
19
|
+
assert len(balances) == 1
|
|
20
|
+
assert balances[0].balance == Decimal('0.00075763')
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_parse_zero_balance():
|
|
24
|
+
api = BitapsLitecoinApi()
|
|
25
|
+
fetch_result = FetchResult(data={'data': {'balance': 0}})
|
|
26
|
+
result = api.parse_balances(fetch_result)
|
|
27
|
+
assert result.data is None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_parse_empty_response():
|
|
31
|
+
api = BitapsLitecoinApi()
|
|
32
|
+
fetch_result = FetchResult(data=None)
|
|
33
|
+
result = api.parse_balances(fetch_result)
|
|
34
|
+
assert result.data is None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.fixture
|
|
38
|
+
def bitaps_ltc_balance_response():
|
|
39
|
+
return read_file('data/bitaps_ltc_balance_response.json')
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from blockapi.test.v2.api.conftest import read_file
|
|
6
|
+
from blockapi.test.v2.test_data import ltc_test_address
|
|
7
|
+
from blockapi.v2.api.litecoinspace import LitecoinSpaceApi
|
|
8
|
+
from blockapi.v2.models import FetchResult
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_fetch_balances(requests_mock, litecoinspace_balance_response):
|
|
12
|
+
requests_mock.get(
|
|
13
|
+
f'https://litecoinspace.org/api/address/{ltc_test_address}',
|
|
14
|
+
text=litecoinspace_balance_response,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
api = LitecoinSpaceApi()
|
|
18
|
+
balances = api.get_balance(ltc_test_address)
|
|
19
|
+
assert len(balances) == 1
|
|
20
|
+
assert balances[0].balance == Decimal('0.00075763')
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_parse_zero_balance():
|
|
24
|
+
api = LitecoinSpaceApi()
|
|
25
|
+
fetch_result = FetchResult(
|
|
26
|
+
data={
|
|
27
|
+
'chain_stats': {
|
|
28
|
+
'funded_txo_sum': 100,
|
|
29
|
+
'spent_txo_sum': 100,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
result = api.parse_balances(fetch_result)
|
|
34
|
+
assert result.data is None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_parse_empty_response():
|
|
38
|
+
api = LitecoinSpaceApi()
|
|
39
|
+
fetch_result = FetchResult(data=None)
|
|
40
|
+
result = api.parse_balances(fetch_result)
|
|
41
|
+
assert result.data is None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@pytest.fixture
|
|
45
|
+
def litecoinspace_balance_response():
|
|
46
|
+
return read_file('data/litecoinspace_balance_response.json')
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from blockapi.v2.api.bitaps import BitapsLitecoinApi
|
|
1
2
|
from blockapi.v2.api.blockchain_info import BlockchainInfoApi
|
|
2
3
|
from blockapi.v2.api.blockchainos import BlockchainosApi
|
|
3
4
|
from blockapi.v2.api.blockchair import (
|
|
@@ -9,6 +10,7 @@ from blockapi.v2.api.blockchair import (
|
|
|
9
10
|
from blockapi.v2.api.debank import DebankApi, DebankApp, DebankPrediction
|
|
10
11
|
from blockapi.v2.api.ethplorer import EthplorerApi
|
|
11
12
|
from blockapi.v2.api.haskoin import HaskoinApi
|
|
13
|
+
from blockapi.v2.api.litecoinspace import LitecoinSpaceApi
|
|
12
14
|
from blockapi.v2.api.optimistic_etherscan import OptimismEtherscanApi
|
|
13
15
|
from blockapi.v2.api.perpetual import PerpetualApi, perp_contract_address
|
|
14
16
|
from blockapi.v2.api.solana import SolanaApi, SolscanApi
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from blockapi.v2.base import BalanceMixin, BlockchainApi
|
|
2
|
+
from blockapi.v2.coins import COIN_LTC
|
|
3
|
+
from blockapi.v2.models import (
|
|
4
|
+
ApiOptions,
|
|
5
|
+
AssetType,
|
|
6
|
+
BalanceItem,
|
|
7
|
+
Blockchain,
|
|
8
|
+
FetchResult,
|
|
9
|
+
ParseResult,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BitapsLitecoinApi(BlockchainApi, BalanceMixin):
|
|
14
|
+
"""
|
|
15
|
+
Coin: Litecoin
|
|
16
|
+
API docs: https://developer.bitaps.com/
|
|
17
|
+
Explorer: https://ltc.bitaps.com
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
coin = COIN_LTC
|
|
21
|
+
api_options = ApiOptions(
|
|
22
|
+
blockchain=Blockchain.LITECOIN,
|
|
23
|
+
base_url='https://api.bitaps.com/ltc/v1/',
|
|
24
|
+
rate_limit=0.1,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
supported_requests = {
|
|
28
|
+
'get_balance': 'blockchain/address/state/{address}',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
def fetch_balances(self, address: str) -> FetchResult:
|
|
32
|
+
return self.get_data('get_balance', address=address)
|
|
33
|
+
|
|
34
|
+
def parse_balances(self, fetch_result: FetchResult) -> ParseResult:
|
|
35
|
+
if not fetch_result.data:
|
|
36
|
+
return ParseResult()
|
|
37
|
+
|
|
38
|
+
data = fetch_result.data.get('data', {})
|
|
39
|
+
balance_raw = data.get('balance')
|
|
40
|
+
|
|
41
|
+
if not balance_raw:
|
|
42
|
+
return ParseResult()
|
|
43
|
+
|
|
44
|
+
return ParseResult(
|
|
45
|
+
data=[
|
|
46
|
+
BalanceItem.from_api(
|
|
47
|
+
balance_raw=balance_raw,
|
|
48
|
+
coin=self.coin,
|
|
49
|
+
asset_type=AssetType.AVAILABLE,
|
|
50
|
+
raw=fetch_result.data,
|
|
51
|
+
)
|
|
52
|
+
]
|
|
53
|
+
)
|
|
@@ -36,6 +36,7 @@ from blockapi.v2.models import (
|
|
|
36
36
|
DebankApp,
|
|
37
37
|
DebankModelApp,
|
|
38
38
|
DebankModelAppPortfolioItem,
|
|
39
|
+
DebankModelAppStats,
|
|
39
40
|
DebankModelPredictionDetail,
|
|
40
41
|
DebankPrediction,
|
|
41
42
|
FetchResult,
|
|
@@ -70,6 +71,7 @@ class DebankModelPoolItemDetail(BaseModel):
|
|
|
70
71
|
description: Optional[str] = None
|
|
71
72
|
health_rate: Optional[float] = None
|
|
72
73
|
unlock_at: Optional[float] = None
|
|
74
|
+
debt_ratio: Optional[float] = None
|
|
73
75
|
token_list: Optional[list[dict]] = None
|
|
74
76
|
supply_token_list: Optional[list[dict]] = None
|
|
75
77
|
borrow_token_list: Optional[list[dict]] = None
|
|
@@ -90,6 +92,9 @@ class DebankModelPortfolioItem(BaseModel):
|
|
|
90
92
|
pool_id: Optional[str] = None
|
|
91
93
|
pool: Optional[DebankModelPoolItem] = None
|
|
92
94
|
position_index: Optional[str] = None
|
|
95
|
+
stats: DebankModelAppStats
|
|
96
|
+
detail_types: list[str]
|
|
97
|
+
update_at: float
|
|
93
98
|
|
|
94
99
|
@validator('pool')
|
|
95
100
|
def require_pool_or_pool_id(cls, v, values, **kwargs):
|
|
@@ -481,6 +486,12 @@ class DebankPortfolioParser:
|
|
|
481
486
|
locked_until=locked_until,
|
|
482
487
|
health_rate=health_rate,
|
|
483
488
|
items=[],
|
|
489
|
+
detail_types=item.detail_types,
|
|
490
|
+
asset_usd_value=item.stats.asset_usd_value,
|
|
491
|
+
debt_usd_value=item.stats.debt_usd_value,
|
|
492
|
+
net_usd_value=item.stats.net_usd_value,
|
|
493
|
+
debt_ratio=detail.debt_ratio,
|
|
494
|
+
update_at=item.update_at,
|
|
484
495
|
)
|
|
485
496
|
|
|
486
497
|
items = list(self._parse_balances(detail, item, pool.pool_info))
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from blockapi.v2.base import BalanceMixin, BlockchainApi
|
|
2
|
+
from blockapi.v2.coins import COIN_LTC
|
|
3
|
+
from blockapi.v2.models import (
|
|
4
|
+
ApiOptions,
|
|
5
|
+
AssetType,
|
|
6
|
+
BalanceItem,
|
|
7
|
+
Blockchain,
|
|
8
|
+
FetchResult,
|
|
9
|
+
ParseResult,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LitecoinSpaceApi(BlockchainApi, BalanceMixin):
|
|
14
|
+
"""
|
|
15
|
+
Coin: Litecoin
|
|
16
|
+
API docs: https://litecoinspace.org/docs/api/rest
|
|
17
|
+
Explorer: https://litecoinspace.org
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
coin = COIN_LTC
|
|
21
|
+
api_options = ApiOptions(
|
|
22
|
+
blockchain=Blockchain.LITECOIN,
|
|
23
|
+
base_url='https://litecoinspace.org',
|
|
24
|
+
rate_limit=0.2,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
supported_requests = {
|
|
28
|
+
'get_balance': '/api/address/{address}',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
def fetch_balances(self, address: str) -> FetchResult:
|
|
32
|
+
return self.get_data('get_balance', address=address)
|
|
33
|
+
|
|
34
|
+
def parse_balances(self, fetch_result: FetchResult) -> ParseResult:
|
|
35
|
+
if not fetch_result.data:
|
|
36
|
+
return ParseResult()
|
|
37
|
+
|
|
38
|
+
chain_stats = fetch_result.data.get('chain_stats', {})
|
|
39
|
+
funded = chain_stats.get('funded_txo_sum', 0)
|
|
40
|
+
spent = chain_stats.get('spent_txo_sum', 0)
|
|
41
|
+
balance_raw = funded - spent
|
|
42
|
+
|
|
43
|
+
if not balance_raw:
|
|
44
|
+
return ParseResult()
|
|
45
|
+
|
|
46
|
+
return ParseResult(
|
|
47
|
+
data=[
|
|
48
|
+
BalanceItem.from_api(
|
|
49
|
+
balance_raw=balance_raw,
|
|
50
|
+
coin=self.coin,
|
|
51
|
+
asset_type=AssetType.AVAILABLE,
|
|
52
|
+
raw=fetch_result.data,
|
|
53
|
+
)
|
|
54
|
+
]
|
|
55
|
+
)
|
|
@@ -1163,6 +1163,19 @@ class TransactionItem:
|
|
|
1163
1163
|
)
|
|
1164
1164
|
|
|
1165
1165
|
|
|
1166
|
+
# uint256.max / 1e18 — Aave's sentinel for "no debt / infinite health factor"
|
|
1167
|
+
_HEALTH_RATE_SENTINEL_THRESHOLD = Decimal('1e18')
|
|
1168
|
+
|
|
1169
|
+
|
|
1170
|
+
def _normalize_health_rate(value) -> Optional[Decimal]:
|
|
1171
|
+
if value is None:
|
|
1172
|
+
return None
|
|
1173
|
+
d = to_decimal(value)
|
|
1174
|
+
if d >= _HEALTH_RATE_SENTINEL_THRESHOLD:
|
|
1175
|
+
return None
|
|
1176
|
+
return d
|
|
1177
|
+
|
|
1178
|
+
|
|
1166
1179
|
@attr.s(auto_attribs=True, slots=True, frozen=True)
|
|
1167
1180
|
class Pool:
|
|
1168
1181
|
pool_info: PoolInfo
|
|
@@ -1170,6 +1183,12 @@ class Pool:
|
|
|
1170
1183
|
items: List[BalanceItem]
|
|
1171
1184
|
locked_until: Optional[datetime] = attr.ib(default=None)
|
|
1172
1185
|
health_rate: Optional[Decimal] = attr.ib(default=None)
|
|
1186
|
+
detail_types: List[str] = attr.ib(factory=list)
|
|
1187
|
+
asset_usd_value: Decimal = attr.ib(default=Decimal('0'))
|
|
1188
|
+
debt_usd_value: Decimal = attr.ib(default=Decimal('0'))
|
|
1189
|
+
net_usd_value: Decimal = attr.ib(default=Decimal('0'))
|
|
1190
|
+
debt_ratio: Optional[Decimal] = attr.ib(default=None)
|
|
1191
|
+
update_at: Optional[datetime] = attr.ib(default=None)
|
|
1173
1192
|
|
|
1174
1193
|
@classmethod
|
|
1175
1194
|
def from_api(
|
|
@@ -1180,13 +1199,25 @@ class Pool:
|
|
|
1180
1199
|
locked_until: Optional[Union[int, str, float]] = None,
|
|
1181
1200
|
health_rate: Optional[Union[float, str]] = None,
|
|
1182
1201
|
items: List[BalanceItem],
|
|
1202
|
+
detail_types: Optional[List[str]] = None,
|
|
1203
|
+
asset_usd_value: Union[float, str] = 0,
|
|
1204
|
+
debt_usd_value: Union[float, str] = 0,
|
|
1205
|
+
net_usd_value: Union[float, str] = 0,
|
|
1206
|
+
debt_ratio: Optional[Union[float, str]] = None,
|
|
1207
|
+
update_at: Optional[Union[int, str, float]] = None,
|
|
1183
1208
|
) -> 'Pool':
|
|
1184
1209
|
return cls(
|
|
1185
1210
|
pool_info=pool_info,
|
|
1186
1211
|
protocol=protocol,
|
|
1187
1212
|
items=items,
|
|
1188
1213
|
locked_until=(parse_dt(locked_until) if locked_until is not None else None),
|
|
1189
|
-
health_rate=
|
|
1214
|
+
health_rate=_normalize_health_rate(health_rate),
|
|
1215
|
+
detail_types=detail_types or [],
|
|
1216
|
+
asset_usd_value=to_decimal(asset_usd_value),
|
|
1217
|
+
debt_usd_value=to_decimal(debt_usd_value),
|
|
1218
|
+
net_usd_value=to_decimal(net_usd_value),
|
|
1219
|
+
debt_ratio=to_decimal(debt_ratio) if debt_ratio is not None else None,
|
|
1220
|
+
update_at=(parse_dt(update_at) if update_at is not None else None),
|
|
1190
1221
|
)
|
|
1191
1222
|
|
|
1192
1223
|
def append_items(self, items: List[BalanceItem]) -> None:
|
|
@@ -26,6 +26,7 @@ blockapi/test/v2/test_models.py
|
|
|
26
26
|
blockapi/test/v2/api/__init__.py
|
|
27
27
|
blockapi/test/v2/api/conftest.py
|
|
28
28
|
blockapi/test/v2/api/fake_sleep_provider.py
|
|
29
|
+
blockapi/test/v2/api/test_bitaps_ltc.py
|
|
29
30
|
blockapi/test/v2/api/test_blockchain_info.py
|
|
30
31
|
blockapi/test/v2/api/test_blockchainos.py
|
|
31
32
|
blockapi/test/v2/api/test_blockchair_btc.py
|
|
@@ -34,6 +35,7 @@ blockapi/test/v2/api/test_blockchair_ltc.py
|
|
|
34
35
|
blockapi/test/v2/api/test_cosmos.py
|
|
35
36
|
blockapi/test/v2/api/test_ethplorer.py
|
|
36
37
|
blockapi/test/v2/api/test_haskoin.py
|
|
38
|
+
blockapi/test/v2/api/test_litecoinspace.py
|
|
37
39
|
blockapi/test/v2/api/test_multisources.py
|
|
38
40
|
blockapi/test/v2/api/test_optimistic_etherscan.py
|
|
39
41
|
blockapi/test/v2/api/test_solana.py
|
|
@@ -65,6 +67,7 @@ blockapi/v2/coin_mapping.py
|
|
|
65
67
|
blockapi/v2/coins.py
|
|
66
68
|
blockapi/v2/models.py
|
|
67
69
|
blockapi/v2/api/__init__.py
|
|
70
|
+
blockapi/v2/api/bitaps.py
|
|
68
71
|
blockapi/v2/api/blockchain_info.py
|
|
69
72
|
blockapi/v2/api/blockchainos.py
|
|
70
73
|
blockapi/v2/api/blockchair.py
|
|
@@ -73,6 +76,7 @@ blockapi/v2/api/debank.py
|
|
|
73
76
|
blockapi/v2/api/debank_maps.py
|
|
74
77
|
blockapi/v2/api/ethplorer.py
|
|
75
78
|
blockapi/v2/api/haskoin.py
|
|
79
|
+
blockapi/v2/api/litecoinspace.py
|
|
76
80
|
blockapi/v2/api/optimistic_etherscan.py
|
|
77
81
|
blockapi/v2/api/solana.py
|
|
78
82
|
blockapi/v2/api/subscan.py
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|