blockapi 2.9.0__tar.gz → 2.10.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.9.0 → blockapi-2.10.0}/PKG-INFO +1 -1
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_terra.py +47 -1
- blockapi-2.10.0/blockapi/v2/api/terra.py +118 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi.egg-info/PKG-INFO +1 -1
- {blockapi-2.9.0 → blockapi-2.10.0}/setup.py +1 -1
- blockapi-2.9.0/blockapi/v2/api/terra.py +0 -59
- {blockapi-2.9.0 → blockapi-2.10.0}/LICENSE.md +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/README.md +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/services.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/test_blockapi.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/test_num.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/test_random_user_agent.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/conftest.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/covalenth/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/covalenth/test_ethereum.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/fake_sleep_provider.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/nft/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/nft/test_magic_eden.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/nft/test_opensea.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/nft/test_simple_hash.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/nft/test_unisat.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/perpetual/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/perpetual/test_perpetual.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/synthetix/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/synthetix/test_synthetix.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_bitaps_ltc.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_blockchain_info.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_blockchainos.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_blockchair_btc.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_blockchair_doge.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_blockchair_ltc.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_cosmos.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_ethplorer.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_haskoin.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_litecoinspace.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_multisources.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_optimistic_etherscan.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_solana.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_subscan_polkadot.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_sui.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_trezor_btc.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/api/test_trezor_zec.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/test_base.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/test_blockchain_api.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/test_blockchain_mapping.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/test_data.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/test_enumerate_classes.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/test_generic.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test/v2/test_models.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/test_data.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/utils/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/utils/address.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/utils/datetime.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/utils/num.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/utils/user_agent.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/bitaps.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/blockchain_info.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/blockchainos.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/blockchair.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/cosmos.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/arbitrum.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/astar.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/avalanche.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/axie.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/base.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/binance_smart_chain.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/ethereum.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/fantom.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/heco.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/iotex.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/klaytn.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/moonbeam.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/palm.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/polygon.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/covalenth/rsk.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/debank.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/debank_maps.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/ethplorer.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/haskoin.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/litecoinspace.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/nft/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/nft/magic_eden.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/nft/opensea.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/nft/simple_hash.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/nft/unisat.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/optimistic_etherscan.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/perpetual/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/perpetual/perp_abi.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/perpetual/perpetual.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/solana.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/subscan.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/sui.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/synthetix/__init__.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/synthetix/synthetix.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/synthetix/synthetix_abi.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/trezor.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/api/web3_utils.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/base.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/blockchain_mapping.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/coin_mapping.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/coins.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi/v2/models.py +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi.egg-info/SOURCES.txt +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi.egg-info/dependency_links.txt +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi.egg-info/requires.txt +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/blockapi.egg-info/top_level.txt +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/pyproject.toml +0 -0
- {blockapi-2.9.0 → blockapi-2.10.0}/setup.cfg +0 -0
|
@@ -3,7 +3,7 @@ from decimal import Decimal
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
5
|
from blockapi.v2.api.terra import TerraApi
|
|
6
|
-
from blockapi.v2.models import AssetType, Blockchain
|
|
6
|
+
from blockapi.v2.models import AssetType, BalanceItem, Blockchain, Coin, CoinInfo
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@pytest.fixture()
|
|
@@ -257,6 +257,52 @@ def test_get_balance_with_ibc_tokens(
|
|
|
257
257
|
assert 'ibc' in rowan.coin.standards
|
|
258
258
|
|
|
259
259
|
|
|
260
|
+
def _make_balance(address, balance_raw, coingecko_id):
|
|
261
|
+
return BalanceItem(
|
|
262
|
+
balance=Decimal(balance_raw) / Decimal(10**6),
|
|
263
|
+
balance_raw=Decimal(balance_raw),
|
|
264
|
+
raw={'denom': address, 'amount': balance_raw},
|
|
265
|
+
coin=Coin(
|
|
266
|
+
symbol='X',
|
|
267
|
+
name='X',
|
|
268
|
+
decimals=6,
|
|
269
|
+
blockchain=Blockchain.TERRA,
|
|
270
|
+
address=address,
|
|
271
|
+
standards=[],
|
|
272
|
+
info=CoinInfo(coingecko_id=coingecko_id),
|
|
273
|
+
),
|
|
274
|
+
asset_type=AssetType.AVAILABLE,
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def test_merge_duplicate_balances():
|
|
279
|
+
"""Two balances share a coingecko_id and merge; two distinct ones do not."""
|
|
280
|
+
balances = [
|
|
281
|
+
_make_balance('ibc/AAAA', '100', 'secret'),
|
|
282
|
+
_make_balance('ibc/BBBB', '200', 'secret'),
|
|
283
|
+
_make_balance('uluna', '1000000', 'terra-luna'),
|
|
284
|
+
_make_balance('ibc/CCCC', '50', None),
|
|
285
|
+
]
|
|
286
|
+
|
|
287
|
+
merged = TerraApi._merge_duplicate_balances(balances)
|
|
288
|
+
|
|
289
|
+
assert len(merged) == 3
|
|
290
|
+
|
|
291
|
+
secret = next(b for b in merged if b.coin.info.coingecko_id == 'secret')
|
|
292
|
+
assert secret.balance_raw == Decimal('300')
|
|
293
|
+
assert secret.balance == Decimal('0.0003')
|
|
294
|
+
assert secret.raw['merged_count'] == 2
|
|
295
|
+
assert len(secret.raw['merged']) == 2
|
|
296
|
+
|
|
297
|
+
lunc = next(b for b in merged if b.coin.info.coingecko_id == 'terra-luna')
|
|
298
|
+
assert lunc.balance_raw == Decimal('1000000')
|
|
299
|
+
assert 'merged' not in lunc.raw
|
|
300
|
+
|
|
301
|
+
no_cg = next(b for b in merged if b.coin.info.coingecko_id is None)
|
|
302
|
+
assert no_cg.balance_raw == Decimal('50')
|
|
303
|
+
assert 'merged' not in no_cg.raw
|
|
304
|
+
|
|
305
|
+
|
|
260
306
|
def test_unbonding_included_in_staked(terra_api, requests_mock):
|
|
261
307
|
requests_mock.get(
|
|
262
308
|
f'{BASE_URL}/cosmos/bank/v1beta1/balances/{ADDRESS}',
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from decimal import Decimal
|
|
3
|
+
from functools import lru_cache
|
|
4
|
+
|
|
5
|
+
import attr
|
|
6
|
+
|
|
7
|
+
from blockapi.v2.api.cosmos import CosmosApiBase
|
|
8
|
+
from blockapi.v2.base import ApiException, ApiOptions
|
|
9
|
+
from blockapi.v2.coins import COIN_TERRA
|
|
10
|
+
from blockapi.v2.models import BalanceItem, Blockchain, Coin
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TerraApi(CosmosApiBase):
|
|
16
|
+
"""
|
|
17
|
+
Terra Classic (LUNC) via standard Cosmos LCD endpoints.
|
|
18
|
+
Explorer: https://finder.terra.money
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
coin = COIN_TERRA
|
|
22
|
+
TOKENS_MAP_BLOCKCHAIN_KEY = 'terra'
|
|
23
|
+
api_options = ApiOptions(
|
|
24
|
+
blockchain=Blockchain.TERRA,
|
|
25
|
+
base_url='https://terra-classic-fcd.publicnode.com/',
|
|
26
|
+
rate_limit=CosmosApiBase.API_BASE_RATE_LIMIT,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
supported_requests = {
|
|
30
|
+
**CosmosApiBase.supported_requests,
|
|
31
|
+
'get_ibc_denom_trace': '/ibc/apps/transfer/v1/denom_traces/{hash}',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
def get_balance(
|
|
35
|
+
self, address: str, merge_duplicates: bool = True
|
|
36
|
+
) -> list[BalanceItem]:
|
|
37
|
+
balances = super().get_balance(address)
|
|
38
|
+
if merge_duplicates:
|
|
39
|
+
balances = self._merge_duplicate_balances(balances)
|
|
40
|
+
return balances
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def _merge_duplicate_balances(
|
|
44
|
+
balances: list[BalanceItem],
|
|
45
|
+
) -> list[BalanceItem]:
|
|
46
|
+
"""
|
|
47
|
+
Merge balances that map to the same upstream coin (same coingecko_id
|
|
48
|
+
+ asset_type) into a single BalanceItem. Distinct IBC denoms that
|
|
49
|
+
resolve to the same currency (e.g. SCRT via two channels) collapse
|
|
50
|
+
into one entry. Items without a coingecko_id are left untouched to
|
|
51
|
+
avoid collapsing unrelated unknown tokens.
|
|
52
|
+
|
|
53
|
+
Merged items carry `raw = {'merged': [...originals], 'merged_count': N}`.
|
|
54
|
+
"""
|
|
55
|
+
groups: dict[tuple, list[BalanceItem]] = {}
|
|
56
|
+
order: list[tuple] = []
|
|
57
|
+
|
|
58
|
+
for idx, b in enumerate(balances):
|
|
59
|
+
coingecko_id = b.coin.info.coingecko_id if b.coin and b.coin.info else None
|
|
60
|
+
if coingecko_id:
|
|
61
|
+
key = (str(coingecko_id), b.asset_type)
|
|
62
|
+
else:
|
|
63
|
+
key = ('__unique__', idx)
|
|
64
|
+
if key not in groups:
|
|
65
|
+
groups[key] = []
|
|
66
|
+
order.append(key)
|
|
67
|
+
groups[key].append(b)
|
|
68
|
+
|
|
69
|
+
merged: list[BalanceItem] = []
|
|
70
|
+
for key in order:
|
|
71
|
+
group = groups[key]
|
|
72
|
+
if len(group) == 1:
|
|
73
|
+
merged.append(group[0])
|
|
74
|
+
continue
|
|
75
|
+
head = group[0]
|
|
76
|
+
merged.append(
|
|
77
|
+
attr.evolve(
|
|
78
|
+
head,
|
|
79
|
+
balance=sum((b.balance for b in group), Decimal(0)),
|
|
80
|
+
balance_raw=sum((b.balance_raw for b in group), Decimal(0)),
|
|
81
|
+
raw={
|
|
82
|
+
'merged': [b.raw for b in group],
|
|
83
|
+
'merged_count': len(group),
|
|
84
|
+
},
|
|
85
|
+
)
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return merged
|
|
89
|
+
|
|
90
|
+
def create_default_coin(self, denom: str) -> Coin:
|
|
91
|
+
if denom.startswith('ibc/'):
|
|
92
|
+
return self._resolve_ibc_denom(denom)
|
|
93
|
+
|
|
94
|
+
return super().create_default_coin(denom)
|
|
95
|
+
|
|
96
|
+
@lru_cache(maxsize=64)
|
|
97
|
+
def _resolve_ibc_denom(self, denom: str) -> Coin:
|
|
98
|
+
hash_ = denom.split('/')[1]
|
|
99
|
+
try:
|
|
100
|
+
response = self.get('get_ibc_denom_trace', hash=hash_)
|
|
101
|
+
base_denom = response['denom_trace']['base_denom']
|
|
102
|
+
symbol = (
|
|
103
|
+
base_denom.lstrip('ux').upper()
|
|
104
|
+
if base_denom.startswith(('u', 'x'))
|
|
105
|
+
else base_denom.upper()
|
|
106
|
+
)
|
|
107
|
+
except (ApiException, KeyError) as e:
|
|
108
|
+
logger.warning(f'Failed to resolve IBC denom {denom}: {e}')
|
|
109
|
+
return super().create_default_coin(denom)
|
|
110
|
+
|
|
111
|
+
return Coin.from_api(
|
|
112
|
+
symbol=symbol,
|
|
113
|
+
name=symbol,
|
|
114
|
+
decimals=self.coin.decimals,
|
|
115
|
+
blockchain=self.api_options.blockchain,
|
|
116
|
+
address=denom,
|
|
117
|
+
standards=['ibc'],
|
|
118
|
+
)
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from functools import lru_cache
|
|
3
|
-
|
|
4
|
-
from blockapi.v2.api.cosmos import CosmosApiBase
|
|
5
|
-
from blockapi.v2.base import ApiException, ApiOptions
|
|
6
|
-
from blockapi.v2.coins import COIN_TERRA
|
|
7
|
-
from blockapi.v2.models import Blockchain, Coin
|
|
8
|
-
|
|
9
|
-
logger = logging.getLogger(__name__)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class TerraApi(CosmosApiBase):
|
|
13
|
-
"""
|
|
14
|
-
Terra Classic (LUNC) via standard Cosmos LCD endpoints.
|
|
15
|
-
Explorer: https://finder.terra.money
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
coin = COIN_TERRA
|
|
19
|
-
TOKENS_MAP_BLOCKCHAIN_KEY = 'terra'
|
|
20
|
-
api_options = ApiOptions(
|
|
21
|
-
blockchain=Blockchain.TERRA,
|
|
22
|
-
base_url='https://terra-classic-fcd.publicnode.com/',
|
|
23
|
-
rate_limit=CosmosApiBase.API_BASE_RATE_LIMIT,
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
supported_requests = {
|
|
27
|
-
**CosmosApiBase.supported_requests,
|
|
28
|
-
'get_ibc_denom_trace': '/ibc/apps/transfer/v1/denom_traces/{hash}',
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
def create_default_coin(self, denom: str) -> Coin:
|
|
32
|
-
if denom.startswith('ibc/'):
|
|
33
|
-
return self._resolve_ibc_denom(denom)
|
|
34
|
-
|
|
35
|
-
return super().create_default_coin(denom)
|
|
36
|
-
|
|
37
|
-
@lru_cache(maxsize=64)
|
|
38
|
-
def _resolve_ibc_denom(self, denom: str) -> Coin:
|
|
39
|
-
hash_ = denom.split('/')[1]
|
|
40
|
-
try:
|
|
41
|
-
response = self.get('get_ibc_denom_trace', hash=hash_)
|
|
42
|
-
base_denom = response['denom_trace']['base_denom']
|
|
43
|
-
symbol = (
|
|
44
|
-
base_denom.lstrip('ux').upper()
|
|
45
|
-
if base_denom.startswith(('u', 'x'))
|
|
46
|
-
else base_denom.upper()
|
|
47
|
-
)
|
|
48
|
-
except (ApiException, KeyError) as e:
|
|
49
|
-
logger.warning(f'Failed to resolve IBC denom {denom}: {e}')
|
|
50
|
-
return super().create_default_coin(denom)
|
|
51
|
-
|
|
52
|
-
return Coin.from_api(
|
|
53
|
-
symbol=symbol,
|
|
54
|
-
name=symbol,
|
|
55
|
-
decimals=self.coin.decimals,
|
|
56
|
-
blockchain=self.api_options.blockchain,
|
|
57
|
-
address=denom,
|
|
58
|
-
standards=['ibc'],
|
|
59
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|