blockapi 2.1.1__tar.gz → 2.2.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.1.1 → blockapi-2.2.0}/PKG-INFO +1 -1
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/__init__.py +6 -1
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/debank.py +127 -1
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/models.py +178 -1
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi.egg-info/PKG-INFO +1 -1
- {blockapi-2.1.1 → blockapi-2.2.0}/setup.py +1 -1
- {blockapi-2.1.1 → blockapi-2.2.0}/LICENSE.md +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/README.md +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/services.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/test_blockapi.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/test_num.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/test_random_user_agent.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/conftest.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/covalenth/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/covalenth/test_ethereum.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/fake_sleep_provider.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/nft/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/nft/test_magic_eden.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/nft/test_opensea.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/nft/test_simple_hash.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/nft/test_unisat.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/perpetual/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/perpetual/test_perpetual.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/synthetix/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/synthetix/test_synthetix.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_blockchainos.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_blockchair_btc.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_blockchair_doge.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_blockchair_ltc.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_cosmos.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_ethplorer.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_multisources.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_optimistic_etherscan.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_solana.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_subscan_polkadot.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_sui.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/api/test_trezor_btc.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/test_base.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/test_blockchain_api.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/test_blockchain_mapping.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/test_data.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/test_enumerate_classes.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/test_generic.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test/v2/test_models.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/test_data.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/utils/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/utils/address.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/utils/datetime.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/utils/num.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/utils/user_agent.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/blockchainos.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/blockchair.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/cosmos.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/arbitrum.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/astar.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/avalanche.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/axie.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/base.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/binance_smart_chain.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/ethereum.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/fantom.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/heco.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/iotex.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/klaytn.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/moonbeam.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/palm.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/polygon.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/covalenth/rsk.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/debank_maps.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/ethplorer.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/nft/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/nft/magic_eden.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/nft/opensea.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/nft/simple_hash.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/nft/unisat.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/optimistic_etherscan.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/perpetual/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/perpetual/perp_abi.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/perpetual/perpetual.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/solana.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/subscan.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/sui.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/synthetix/__init__.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/synthetix/synthetix.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/synthetix/synthetix_abi.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/terra.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/trezor.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/api/web3_utils.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/base.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/blockchain_mapping.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/coin_mapping.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi/v2/coins.py +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi.egg-info/SOURCES.txt +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi.egg-info/dependency_links.txt +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi.egg-info/requires.txt +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/blockapi.egg-info/top_level.txt +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/pyproject.toml +0 -0
- {blockapi-2.1.1 → blockapi-2.2.0}/setup.cfg +0 -0
|
@@ -5,7 +5,12 @@ from blockapi.v2.api.blockchair import (
|
|
|
5
5
|
BlockchairDogecoinApi,
|
|
6
6
|
BlockchairLitecoinApi,
|
|
7
7
|
)
|
|
8
|
-
from blockapi.v2.api.debank import
|
|
8
|
+
from blockapi.v2.api.debank import (
|
|
9
|
+
DebankApi,
|
|
10
|
+
DebankApp,
|
|
11
|
+
DebankAppDeposit,
|
|
12
|
+
DebankPrediction,
|
|
13
|
+
)
|
|
9
14
|
from blockapi.v2.api.ethplorer import EthplorerApi
|
|
10
15
|
from blockapi.v2.api.optimistic_etherscan import OptimismEtherscanApi
|
|
11
16
|
from blockapi.v2.api.perpetual import PerpetualApi, perp_contract_address
|
|
@@ -9,7 +9,7 @@ from pydantic import BaseModel, validator
|
|
|
9
9
|
|
|
10
10
|
from blockapi.utils.address import make_checksum_address
|
|
11
11
|
from blockapi.utils.datetime import parse_dt
|
|
12
|
-
from blockapi.utils.num import decimals_to_raw
|
|
12
|
+
from blockapi.utils.num import decimals_to_raw, to_decimal
|
|
13
13
|
from blockapi.v2.api.debank_maps import (
|
|
14
14
|
COINGECKO_IDS_BY_CONTRACTS,
|
|
15
15
|
DEBANK_ASSET_TYPES,
|
|
@@ -35,6 +35,13 @@ from blockapi.v2.models import (
|
|
|
35
35
|
Pool,
|
|
36
36
|
PoolInfo,
|
|
37
37
|
Protocol,
|
|
38
|
+
DebankApp,
|
|
39
|
+
DebankAppDeposit,
|
|
40
|
+
DebankPrediction,
|
|
41
|
+
DebankModelAppPortfolioItem,
|
|
42
|
+
DebankModelApp,
|
|
43
|
+
DebankModelDepositDetail,
|
|
44
|
+
DebankModelPredictionDetail,
|
|
38
45
|
)
|
|
39
46
|
|
|
40
47
|
logger = logging.getLogger(__name__)
|
|
@@ -592,6 +599,109 @@ class DebankPortfolioParser:
|
|
|
592
599
|
return REWARD_ASSET_TYPE_MAP.get(asset_type, asset_type)
|
|
593
600
|
|
|
594
601
|
|
|
602
|
+
class DebankAppParser:
|
|
603
|
+
"""Parser for Debank complex_app_list responses."""
|
|
604
|
+
|
|
605
|
+
def parse(self, response: list) -> list[DebankApp]:
|
|
606
|
+
"""Parse the full response from get_complex_app_list."""
|
|
607
|
+
if not response:
|
|
608
|
+
return []
|
|
609
|
+
|
|
610
|
+
apps = []
|
|
611
|
+
for item in response:
|
|
612
|
+
app = self._parse_app(item)
|
|
613
|
+
if app:
|
|
614
|
+
apps.append(app)
|
|
615
|
+
|
|
616
|
+
return apps
|
|
617
|
+
|
|
618
|
+
def _parse_app(self, raw_app: dict) -> Optional[DebankApp]:
|
|
619
|
+
"""Parse a single app from the response."""
|
|
620
|
+
try:
|
|
621
|
+
model = DebankModelApp(**raw_app)
|
|
622
|
+
except Exception as e:
|
|
623
|
+
logger.error(f'Failed to parse app: {e}')
|
|
624
|
+
return None
|
|
625
|
+
|
|
626
|
+
deposits = []
|
|
627
|
+
predictions = []
|
|
628
|
+
|
|
629
|
+
for portfolio_item in model.portfolio_item_list:
|
|
630
|
+
detail_types = portfolio_item.detail_types
|
|
631
|
+
|
|
632
|
+
if 'prediction' in detail_types:
|
|
633
|
+
prediction = self._parse_prediction(portfolio_item)
|
|
634
|
+
if prediction:
|
|
635
|
+
predictions.append(prediction)
|
|
636
|
+
else:
|
|
637
|
+
# Parse as deposit (common, etc.)
|
|
638
|
+
deposit = self._parse_deposit(portfolio_item)
|
|
639
|
+
if deposit:
|
|
640
|
+
deposits.append(deposit)
|
|
641
|
+
|
|
642
|
+
return DebankApp.from_api(
|
|
643
|
+
app_id=model.id,
|
|
644
|
+
name=model.name,
|
|
645
|
+
site_url=model.site_url,
|
|
646
|
+
logo_url=model.logo_url,
|
|
647
|
+
has_supported_portfolio=model.has_supported_portfolio,
|
|
648
|
+
deposits=deposits,
|
|
649
|
+
predictions=predictions,
|
|
650
|
+
)
|
|
651
|
+
|
|
652
|
+
def _parse_prediction(
|
|
653
|
+
self, item: DebankModelAppPortfolioItem
|
|
654
|
+
) -> Optional[DebankPrediction]:
|
|
655
|
+
"""Parse a prediction market position."""
|
|
656
|
+
try:
|
|
657
|
+
detail = DebankModelPredictionDetail(**item.detail)
|
|
658
|
+
except Exception as e:
|
|
659
|
+
logger.error(f'Failed to parse prediction detail: {e}')
|
|
660
|
+
return None
|
|
661
|
+
|
|
662
|
+
return DebankPrediction.from_api(
|
|
663
|
+
prediction_name=detail.name,
|
|
664
|
+
side=detail.side,
|
|
665
|
+
amount=detail.amount,
|
|
666
|
+
price=detail.price,
|
|
667
|
+
usd_value=item.stats.net_usd_value,
|
|
668
|
+
claimable=detail.claimable,
|
|
669
|
+
event_end_at=detail.event_end_at,
|
|
670
|
+
is_market_closed=detail.is_market_closed,
|
|
671
|
+
position_index=item.position_index,
|
|
672
|
+
update_at=item.update_at,
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
def _parse_deposit(
|
|
676
|
+
self, item: DebankModelAppPortfolioItem
|
|
677
|
+
) -> Optional[DebankAppDeposit]:
|
|
678
|
+
"""Parse a deposit/common type portfolio item."""
|
|
679
|
+
try:
|
|
680
|
+
detail = DebankModelDepositDetail(**item.detail)
|
|
681
|
+
except Exception as e:
|
|
682
|
+
logger.warning(f'Failed to parse deposit detail: {e}')
|
|
683
|
+
detail = DebankModelDepositDetail()
|
|
684
|
+
|
|
685
|
+
# Collect all tokens from supply, borrow, and reward lists
|
|
686
|
+
tokens = []
|
|
687
|
+
if detail.supply_token_list:
|
|
688
|
+
tokens.extend(detail.supply_token_list)
|
|
689
|
+
if detail.borrow_token_list:
|
|
690
|
+
tokens.extend(detail.borrow_token_list)
|
|
691
|
+
if detail.reward_token_list:
|
|
692
|
+
tokens.extend(detail.reward_token_list)
|
|
693
|
+
|
|
694
|
+
return DebankAppDeposit.from_api(
|
|
695
|
+
name=item.name,
|
|
696
|
+
asset_usd_value=item.stats.asset_usd_value,
|
|
697
|
+
debt_usd_value=item.stats.debt_usd_value,
|
|
698
|
+
net_usd_value=item.stats.net_usd_value,
|
|
699
|
+
tokens=tokens,
|
|
700
|
+
position_index=item.position_index,
|
|
701
|
+
update_at=item.update_at,
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
|
|
595
705
|
class DebankApi(CustomizableBlockchainApi, BalanceMixin, IPortfolio):
|
|
596
706
|
"""
|
|
597
707
|
DeBank OpenApi: https://open.debank.com/
|
|
@@ -613,6 +723,7 @@ class DebankApi(CustomizableBlockchainApi, BalanceMixin, IPortfolio):
|
|
|
613
723
|
'get_portfolio': '/v1/user/all_complex_protocol_list?id={address}',
|
|
614
724
|
'get_protocols': '/v1/protocol/all_list',
|
|
615
725
|
'usage': '/v1/account/units',
|
|
726
|
+
'get_complex_app_list': '/v1/user/complex_app_list?id={address}',
|
|
616
727
|
}
|
|
617
728
|
|
|
618
729
|
default_protocol_cache = DebankProtocolCache()
|
|
@@ -636,6 +747,7 @@ class DebankApi(CustomizableBlockchainApi, BalanceMixin, IPortfolio):
|
|
|
636
747
|
self._protocol_parser, self._balance_parser
|
|
637
748
|
)
|
|
638
749
|
self._usage_parser = DebankUsageParser()
|
|
750
|
+
self._app_parser = DebankAppParser()
|
|
639
751
|
|
|
640
752
|
def fetch_balances(self, address: str) -> FetchResult:
|
|
641
753
|
return self.get_data(
|
|
@@ -652,6 +764,13 @@ class DebankApi(CustomizableBlockchainApi, BalanceMixin, IPortfolio):
|
|
|
652
764
|
address=address,
|
|
653
765
|
)
|
|
654
766
|
|
|
767
|
+
def fetch_debank_apps(self, address: str) -> FetchResult:
|
|
768
|
+
return self.get_data(
|
|
769
|
+
'get_complex_app_list',
|
|
770
|
+
headers=self._headers,
|
|
771
|
+
address=address,
|
|
772
|
+
)
|
|
773
|
+
|
|
655
774
|
def fetch_protocols(self) -> FetchResult:
|
|
656
775
|
return self.get_data(
|
|
657
776
|
'get_protocols',
|
|
@@ -685,6 +804,13 @@ class DebankApi(CustomizableBlockchainApi, BalanceMixin, IPortfolio):
|
|
|
685
804
|
|
|
686
805
|
return self._protocol_parser.parse(response)
|
|
687
806
|
|
|
807
|
+
def parse_debank_apps(self, fetch_result: FetchResult) -> ParseResult:
|
|
808
|
+
if error := self._get_error(fetch_result.data):
|
|
809
|
+
return ParseResult(errors=[error])
|
|
810
|
+
|
|
811
|
+
apps = self._app_parser.parse(fetch_result.data)
|
|
812
|
+
return ParseResult(data=apps)
|
|
813
|
+
|
|
688
814
|
def get_chains(self) -> list[DebankChain]:
|
|
689
815
|
response = self.get('get_chains', headers=self._headers)
|
|
690
816
|
if self._has_error(response):
|
|
@@ -8,6 +8,7 @@ import attr
|
|
|
8
8
|
|
|
9
9
|
from blockapi.utils.datetime import parse_dt
|
|
10
10
|
from blockapi.utils.num import raw_to_decimals, to_decimal, to_int
|
|
11
|
+
from pydantic import BaseModel
|
|
11
12
|
|
|
12
13
|
UNKNOWN = 'unknown'
|
|
13
14
|
|
|
@@ -386,6 +387,7 @@ class AssetType(str, Enum):
|
|
|
386
387
|
LOCKED = 'locked'
|
|
387
388
|
NFT = 'nft'
|
|
388
389
|
PENDING_TRANSACTION = 'pending_transaction'
|
|
390
|
+
PREDICTION = 'prediction'
|
|
389
391
|
PRICED_VESTING = 'priced_vesting'
|
|
390
392
|
REWARDS = 'rewards'
|
|
391
393
|
STAKED = 'staked'
|
|
@@ -1172,6 +1174,181 @@ class Pool:
|
|
|
1172
1174
|
self.items.extend(items)
|
|
1173
1175
|
|
|
1174
1176
|
|
|
1177
|
+
# --- Debank App Models ---
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
class DebankModelAppStats(BaseModel):
|
|
1181
|
+
"""Stats for a portfolio item."""
|
|
1182
|
+
|
|
1183
|
+
asset_usd_value: float
|
|
1184
|
+
debt_usd_value: float
|
|
1185
|
+
net_usd_value: float
|
|
1186
|
+
|
|
1187
|
+
|
|
1188
|
+
class DebankModelPredictionDetail(BaseModel):
|
|
1189
|
+
"""Detail for prediction type portfolio items."""
|
|
1190
|
+
|
|
1191
|
+
name: str
|
|
1192
|
+
side: str
|
|
1193
|
+
amount: float
|
|
1194
|
+
price: float
|
|
1195
|
+
claimable: bool
|
|
1196
|
+
is_market_closed: bool
|
|
1197
|
+
event_end_at: Optional[float] = None
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
class DebankModelDepositDetail(BaseModel):
|
|
1201
|
+
"""Detail for deposit/common type portfolio items."""
|
|
1202
|
+
|
|
1203
|
+
supply_token_list: Optional[list[dict]] = None
|
|
1204
|
+
borrow_token_list: Optional[list[dict]] = None
|
|
1205
|
+
reward_token_list: Optional[list[dict]] = None
|
|
1206
|
+
|
|
1207
|
+
|
|
1208
|
+
class DebankModelAppPortfolioItem(BaseModel):
|
|
1209
|
+
"""Portfolio item within an app."""
|
|
1210
|
+
|
|
1211
|
+
stats: DebankModelAppStats
|
|
1212
|
+
name: str
|
|
1213
|
+
detail_types: list[str]
|
|
1214
|
+
detail: dict
|
|
1215
|
+
position_index: str
|
|
1216
|
+
asset_dict: Optional[dict] = None
|
|
1217
|
+
asset_token_list: Optional[list[dict]] = None
|
|
1218
|
+
update_at: Optional[float] = None
|
|
1219
|
+
proxy_detail: Optional[dict] = None
|
|
1220
|
+
|
|
1221
|
+
|
|
1222
|
+
class DebankModelApp(BaseModel):
|
|
1223
|
+
"""Debank App model from complex_app_list endpoint."""
|
|
1224
|
+
|
|
1225
|
+
id: str
|
|
1226
|
+
name: str
|
|
1227
|
+
portfolio_item_list: list[DebankModelAppPortfolioItem]
|
|
1228
|
+
site_url: Optional[str] = None
|
|
1229
|
+
logo_url: Optional[str] = None
|
|
1230
|
+
has_supported_portfolio: bool = False
|
|
1231
|
+
|
|
1232
|
+
|
|
1233
|
+
@attr.s(auto_attribs=True, slots=True, frozen=True)
|
|
1234
|
+
class DebankPrediction:
|
|
1235
|
+
"""Represents a prediction market position (e.g., Polymarket)."""
|
|
1236
|
+
|
|
1237
|
+
prediction_name: str
|
|
1238
|
+
side: str
|
|
1239
|
+
amount: Decimal
|
|
1240
|
+
price: Decimal
|
|
1241
|
+
usd_value: Decimal
|
|
1242
|
+
claimable: bool
|
|
1243
|
+
event_end_at: Optional[datetime]
|
|
1244
|
+
is_market_closed: bool
|
|
1245
|
+
position_index: Optional[str]
|
|
1246
|
+
update_at: Optional[datetime]
|
|
1247
|
+
|
|
1248
|
+
@classmethod
|
|
1249
|
+
def from_api(
|
|
1250
|
+
cls,
|
|
1251
|
+
*,
|
|
1252
|
+
prediction_name: str,
|
|
1253
|
+
side: str,
|
|
1254
|
+
amount: Union[str, float, int],
|
|
1255
|
+
price: Union[str, float, int],
|
|
1256
|
+
usd_value: Union[str, float, int],
|
|
1257
|
+
claimable: bool,
|
|
1258
|
+
is_market_closed: bool,
|
|
1259
|
+
event_end_at: Optional[Union[int, float]] = None,
|
|
1260
|
+
position_index: Optional[str] = None,
|
|
1261
|
+
update_at: Optional[Union[int, float]] = None,
|
|
1262
|
+
) -> 'DebankPrediction':
|
|
1263
|
+
return cls(
|
|
1264
|
+
prediction_name=prediction_name,
|
|
1265
|
+
side=side,
|
|
1266
|
+
amount=to_decimal(amount),
|
|
1267
|
+
price=to_decimal(price),
|
|
1268
|
+
usd_value=to_decimal(usd_value),
|
|
1269
|
+
claimable=claimable,
|
|
1270
|
+
event_end_at=parse_dt(event_end_at) if event_end_at is not None else None,
|
|
1271
|
+
is_market_closed=is_market_closed,
|
|
1272
|
+
position_index=position_index,
|
|
1273
|
+
update_at=parse_dt(update_at) if update_at is not None else None,
|
|
1274
|
+
)
|
|
1275
|
+
|
|
1276
|
+
|
|
1277
|
+
@attr.s(auto_attribs=True, slots=True, frozen=True)
|
|
1278
|
+
class DebankAppDeposit:
|
|
1279
|
+
"""Represents a deposit/holding within a Debank App (e.g., Polymarket cash deposit)."""
|
|
1280
|
+
|
|
1281
|
+
name: str
|
|
1282
|
+
asset_usd_value: Decimal
|
|
1283
|
+
debt_usd_value: Decimal
|
|
1284
|
+
net_usd_value: Decimal
|
|
1285
|
+
tokens: list[dict] # Raw token data for flexibility
|
|
1286
|
+
position_index: Optional[str]
|
|
1287
|
+
update_at: Optional[datetime]
|
|
1288
|
+
|
|
1289
|
+
@classmethod
|
|
1290
|
+
def from_api(
|
|
1291
|
+
cls,
|
|
1292
|
+
*,
|
|
1293
|
+
name: str,
|
|
1294
|
+
asset_usd_value: Union[str, float, int],
|
|
1295
|
+
debt_usd_value: Union[str, float, int],
|
|
1296
|
+
net_usd_value: Union[str, float, int],
|
|
1297
|
+
position_index: str,
|
|
1298
|
+
tokens: Optional[list[dict]] = None,
|
|
1299
|
+
update_at: Optional[Union[int, float]] = None,
|
|
1300
|
+
) -> 'DebankAppDeposit':
|
|
1301
|
+
return cls(
|
|
1302
|
+
name=name,
|
|
1303
|
+
asset_usd_value=to_decimal(asset_usd_value),
|
|
1304
|
+
debt_usd_value=to_decimal(debt_usd_value),
|
|
1305
|
+
net_usd_value=to_decimal(net_usd_value),
|
|
1306
|
+
tokens=tokens or [],
|
|
1307
|
+
position_index=position_index,
|
|
1308
|
+
update_at=parse_dt(update_at) if update_at else None,
|
|
1309
|
+
)
|
|
1310
|
+
|
|
1311
|
+
@property
|
|
1312
|
+
def token_symbols(self) -> list[str]:
|
|
1313
|
+
"""Get list of token symbols in this deposit."""
|
|
1314
|
+
return [t.get('symbol', t.get('name', '')) for t in self.tokens]
|
|
1315
|
+
|
|
1316
|
+
|
|
1317
|
+
@attr.s(auto_attribs=True, slots=True, frozen=True)
|
|
1318
|
+
class DebankApp:
|
|
1319
|
+
"""Represents a Debank App with its deposits and predictions."""
|
|
1320
|
+
|
|
1321
|
+
app_id: str
|
|
1322
|
+
name: str
|
|
1323
|
+
site_url: Optional[str]
|
|
1324
|
+
logo_url: Optional[str]
|
|
1325
|
+
has_supported_portfolio: bool
|
|
1326
|
+
deposits: list[DebankAppDeposit]
|
|
1327
|
+
predictions: list[DebankPrediction]
|
|
1328
|
+
|
|
1329
|
+
@classmethod
|
|
1330
|
+
def from_api(
|
|
1331
|
+
cls,
|
|
1332
|
+
*,
|
|
1333
|
+
app_id: str,
|
|
1334
|
+
name: str,
|
|
1335
|
+
site_url: Optional[str] = None,
|
|
1336
|
+
logo_url: Optional[str] = None,
|
|
1337
|
+
has_supported_portfolio: bool = False,
|
|
1338
|
+
deposits: Optional[list[DebankAppDeposit]] = None,
|
|
1339
|
+
predictions: Optional[list[DebankPrediction]] = None,
|
|
1340
|
+
) -> 'DebankApp':
|
|
1341
|
+
return cls(
|
|
1342
|
+
app_id=app_id,
|
|
1343
|
+
name=name,
|
|
1344
|
+
site_url=site_url,
|
|
1345
|
+
logo_url=logo_url,
|
|
1346
|
+
has_supported_portfolio=has_supported_portfolio,
|
|
1347
|
+
deposits=deposits or [],
|
|
1348
|
+
predictions=predictions or [],
|
|
1349
|
+
)
|
|
1350
|
+
|
|
1351
|
+
|
|
1175
1352
|
@attr.s(auto_attribs=True, slots=True)
|
|
1176
1353
|
class FetchResult:
|
|
1177
1354
|
status_code: Optional[int] = None
|
|
@@ -1204,7 +1381,7 @@ class FetchResult:
|
|
|
1204
1381
|
@attr.s(auto_attribs=True, slots=True, frozen=True)
|
|
1205
1382
|
class ParseResult:
|
|
1206
1383
|
data: Optional[
|
|
1207
|
-
list[Union[BalanceItem, Pool, NftToken, NftCollection, NftOffer]]
|
|
1384
|
+
list[Union[BalanceItem, Pool, NftToken, NftCollection, NftOffer, DebankApp]]
|
|
1208
1385
|
] = None
|
|
1209
1386
|
warnings: Optional[list[Union[str, dict]]] = None
|
|
1210
1387
|
errors: Optional[list[Union[str, dict]]] = None
|
|
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
|