blockapi 2.10.2__tar.gz → 2.10.4__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.10.2 → blockapi-2.10.4}/PKG-INFO +3 -6
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/__init__.py +0 -1
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/services.py +3 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/nft/test_opensea.py +3 -1
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/nft/test_simple_hash.py +3 -1
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_data.py +0 -6
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_enumerate_classes.py +1 -4
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/utils/datetime.py +6 -1
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/__init__.py +0 -1
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/debank.py +3 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/nft/unisat.py +2 -2
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/base.py +4 -4
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/coins.py +0 -9
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/models.py +4 -3
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi.egg-info/PKG-INFO +3 -6
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi.egg-info/SOURCES.txt +1 -12
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi.egg-info/requires.txt +2 -5
- {blockapi-2.10.2 → blockapi-2.10.4}/setup.py +3 -6
- blockapi-2.10.2/blockapi/test/v2/api/perpetual/test_perpetual.py +0 -94
- blockapi-2.10.2/blockapi/test/v2/api/synthetix/test_synthetix.py +0 -166
- blockapi-2.10.2/blockapi/v2/__init__.py +0 -0
- blockapi-2.10.2/blockapi/v2/api/covalenth/__init__.py +0 -0
- blockapi-2.10.2/blockapi/v2/api/perpetual/__init__.py +0 -1
- blockapi-2.10.2/blockapi/v2/api/perpetual/perp_abi.py +0 -264
- blockapi-2.10.2/blockapi/v2/api/perpetual/perpetual.py +0 -253
- blockapi-2.10.2/blockapi/v2/api/synthetix/__init__.py +0 -7
- blockapi-2.10.2/blockapi/v2/api/synthetix/synthetix.py +0 -431
- blockapi-2.10.2/blockapi/v2/api/synthetix/synthetix_abi.py +0 -5780
- blockapi-2.10.2/blockapi/v2/api/web3_utils.py +0 -142
- {blockapi-2.10.2 → blockapi-2.10.4}/LICENSE.md +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/README.md +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/__init__.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/test_blockapi.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/test_num.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/test_random_user_agent.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/__init__.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/__init__.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/conftest.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/covalenth/__init__.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/covalenth/test_ethereum.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/fake_sleep_provider.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/nft/__init__.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/nft/test_magic_eden.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/nft/test_unisat.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_bitaps_ltc.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_blockchain_info.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_blockchainos.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_blockchair_btc.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_blockchair_doge.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_blockchair_ltc.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_cosmos.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_ethplorer.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_haskoin.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_litecoinspace.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_multisources.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_optimistic_etherscan.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_solana.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_subscan_polkadot.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_sui.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_terra.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_trezor_btc.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/api/test_trezor_zec.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_base.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_blockchain_api.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_blockchain_mapping.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_generic.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test/v2/test_models.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/test_data.py +0 -0
- {blockapi-2.10.2/blockapi/test/v2/api/perpetual → blockapi-2.10.4/blockapi/utils}/__init__.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/utils/address.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/utils/num.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/utils/user_agent.py +0 -0
- {blockapi-2.10.2/blockapi/test/v2/api/synthetix → blockapi-2.10.4/blockapi/v2}/__init__.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/bitaps.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/blockchain_info.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/blockchainos.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/blockchair.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/cosmos.py +0 -0
- {blockapi-2.10.2/blockapi/utils → blockapi-2.10.4/blockapi/v2/api/covalenth}/__init__.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/arbitrum.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/astar.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/avalanche.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/axie.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/base.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/binance_smart_chain.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/ethereum.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/fantom.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/heco.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/iotex.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/klaytn.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/moonbeam.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/palm.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/polygon.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/covalenth/rsk.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/debank_maps.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/ethplorer.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/haskoin.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/litecoinspace.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/nft/__init__.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/nft/magic_eden.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/nft/opensea.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/nft/simple_hash.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/optimistic_etherscan.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/solana.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/subscan.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/sui.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/terra.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/api/trezor.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/blockchain_mapping.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi/v2/coin_mapping.py +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi.egg-info/dependency_links.txt +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/blockapi.egg-info/top_level.txt +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/pyproject.toml +0 -0
- {blockapi-2.10.2 → blockapi-2.10.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blockapi
|
|
3
|
-
Version: 2.10.
|
|
3
|
+
Version: 2.10.4
|
|
4
4
|
Summary: BlockAPI library
|
|
5
5
|
Home-page: https://github.com/crypkit/blockapi
|
|
6
6
|
Author: Devmons s.r.o.
|
|
@@ -9,18 +9,15 @@ Description-Content-Type: text/markdown
|
|
|
9
9
|
License-File: LICENSE.md
|
|
10
10
|
Requires-Dist: requests<3.0,>=2.28
|
|
11
11
|
Requires-Dist: python-dateutil>=2.8.0
|
|
12
|
+
Requires-Dist: cytoolz>=0.12.0
|
|
13
|
+
Requires-Dist: eth-utils>=2.0.0
|
|
12
14
|
Requires-Dist: coinaddrng==1.1.1
|
|
13
|
-
Requires-Dist: web3<8.0.0,>=5.2.2
|
|
14
|
-
Requires-Dist: bs4>=0.0.1
|
|
15
|
-
Requires-Dist: lxml>=4.4.1
|
|
16
15
|
Requires-Dist: pydantic>=1.10.2
|
|
17
|
-
Requires-Dist: marko<2.0.0,>=1.3.0
|
|
18
16
|
Requires-Dist: fake_useragent>=1.1.3
|
|
19
17
|
Requires-Dist: pytest
|
|
20
18
|
Requires-Dist: pytest-vcr
|
|
21
19
|
Requires-Dist: requests_mock>=1.9.3
|
|
22
20
|
Requires-Dist: attrs<23.0.0,>=17.4.0
|
|
23
|
-
Requires-Dist: solders>=0.22.0
|
|
24
21
|
Requires-Dist: base58>=2.1.0
|
|
25
22
|
Requires-Dist: aiohttp<3.14
|
|
26
23
|
Dynamic: author
|
|
@@ -56,6 +56,9 @@ class Service(ABC):
|
|
|
56
56
|
response = reqobj.get(request_url, headers=headers)
|
|
57
57
|
|
|
58
58
|
self.last_response = response
|
|
59
|
+
# Naive local time on purpose: only used to measure elapsed time against
|
|
60
|
+
# datetime.now() in wait_for_next_request (rate limiting), never compared
|
|
61
|
+
# with tz-aware datetimes.
|
|
59
62
|
self.last_response_time = datetime.now()
|
|
60
63
|
|
|
61
64
|
if response.status_code != 200:
|
|
@@ -162,7 +162,9 @@ def test_parse_nfts(requests_mock, api, nfts_response, nfts_next_response):
|
|
|
162
162
|
== 'data:application/json;base64,eyJuYW1lIjoiVW5pc3dhcCAtIDElIC0gUFJJTUUvV0VUSCAtIDMzMC4yMDw+NzgwLjI5In0='
|
|
163
163
|
)
|
|
164
164
|
assert not data.metadata
|
|
165
|
-
assert data.updated_time == datetime.datetime(
|
|
165
|
+
assert data.updated_time == datetime.datetime(
|
|
166
|
+
2023, 8, 15, 13, 56, 39, 759414, tzinfo=datetime.timezone.utc
|
|
167
|
+
)
|
|
166
168
|
assert not data.is_disabled
|
|
167
169
|
assert not data.is_nsfw
|
|
168
170
|
assert data.blockchain == Blockchain.ETHEREUM
|
|
@@ -55,7 +55,9 @@ def test_parse_nfts(requests_mock, api, nfts_response):
|
|
|
55
55
|
)
|
|
56
56
|
assert not data.metadata_url
|
|
57
57
|
assert not data.metadata
|
|
58
|
-
assert data.updated_time == datetime.datetime(
|
|
58
|
+
assert data.updated_time == datetime.datetime(
|
|
59
|
+
2023, 3, 11, 3, 46, 15, tzinfo=datetime.timezone.utc
|
|
60
|
+
)
|
|
59
61
|
assert not data.is_disabled
|
|
60
62
|
assert not data.is_nsfw
|
|
61
63
|
assert data.blockchain == Blockchain.BITCOIN
|
|
@@ -10,7 +10,6 @@ from blockapi.v2.api import (
|
|
|
10
10
|
EthplorerApi,
|
|
11
11
|
KusamaSubscanApi,
|
|
12
12
|
OptimismEtherscanApi,
|
|
13
|
-
PerpetualApi,
|
|
14
13
|
PolkadotSubscanApi,
|
|
15
14
|
SolanaApi,
|
|
16
15
|
SubscanApi,
|
|
@@ -32,7 +31,6 @@ from blockapi.v2.api.covalenth.moonbeam import MoonBeamCovalentApi
|
|
|
32
31
|
from blockapi.v2.api.covalenth.palm import PalmCovalentApi
|
|
33
32
|
from blockapi.v2.api.covalenth.polygon import PolygonCovalentApi
|
|
34
33
|
from blockapi.v2.api.covalenth.rsk import RskCovalentApi
|
|
35
|
-
from blockapi.v2.api.synthetix import SynthetixApi
|
|
36
34
|
|
|
37
35
|
# TODO create method for auto loading all classes
|
|
38
36
|
from blockapi.v2.base import BalanceMixin, IBalance
|
|
@@ -93,8 +91,6 @@ API_CLASSES = [
|
|
|
93
91
|
PolkadotSubscanApi,
|
|
94
92
|
KusamaSubscanApi,
|
|
95
93
|
CosmosApi,
|
|
96
|
-
SynthetixApi,
|
|
97
|
-
PerpetualApi,
|
|
98
94
|
BlockchairBitcoinApi,
|
|
99
95
|
]
|
|
100
96
|
|
|
@@ -187,8 +183,6 @@ def yield_api_balance_classes():
|
|
|
187
183
|
CosmosApiBase,
|
|
188
184
|
CovalentApiBase,
|
|
189
185
|
DebankApi,
|
|
190
|
-
PerpetualApi,
|
|
191
|
-
SynthetixApi,
|
|
192
186
|
SubscanApi,
|
|
193
187
|
TrezorApi,
|
|
194
188
|
),
|
|
@@ -5,7 +5,7 @@ from blockapi.test.v2.test_data import (
|
|
|
5
5
|
yield_api_balance_classes,
|
|
6
6
|
yield_covalent_api_classes,
|
|
7
7
|
)
|
|
8
|
-
from blockapi.v2.api import DebankApi, EthplorerApi
|
|
8
|
+
from blockapi.v2.api import DebankApi, EthplorerApi
|
|
9
9
|
from blockapi.v2.api.covalenth.arbitrum import ArbitrumCovalentApi
|
|
10
10
|
from blockapi.v2.api.covalenth.astar import AstarCovalentApi
|
|
11
11
|
from blockapi.v2.api.covalenth.avalanche import AvalancheCovalentApi
|
|
@@ -20,7 +20,6 @@ from blockapi.v2.api.covalenth.moonbeam import MoonBeamCovalentApi
|
|
|
20
20
|
from blockapi.v2.api.covalenth.palm import PalmCovalentApi
|
|
21
21
|
from blockapi.v2.api.covalenth.polygon import PolygonCovalentApi
|
|
22
22
|
from blockapi.v2.api.covalenth.rsk import RskCovalentApi
|
|
23
|
-
from blockapi.v2.api.synthetix import SynthetixApi
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
def test_enumerate_subclasses():
|
|
@@ -29,8 +28,6 @@ def test_enumerate_subclasses():
|
|
|
29
28
|
assert classes
|
|
30
29
|
assert EthplorerApi.__name__ in classes
|
|
31
30
|
assert DebankApi.__name__ not in classes
|
|
32
|
-
assert PerpetualApi.__name__ not in classes
|
|
33
|
-
assert SynthetixApi.__name__ not in classes
|
|
34
31
|
|
|
35
32
|
for cls in classes:
|
|
36
33
|
assert 'Base' not in cls
|
|
@@ -12,7 +12,12 @@ def parse_dt(dt: Union[str, int, float]) -> datetime:
|
|
|
12
12
|
try:
|
|
13
13
|
return datetime.fromtimestamp(int(dt), tz=timezone.utc)
|
|
14
14
|
except ValueError:
|
|
15
|
-
|
|
15
|
+
parsed = parse_date(dt)
|
|
16
|
+
# Assume UTC for strings that carry no timezone, so parse_dt always
|
|
17
|
+
# returns a tz-aware datetime (consistent with the numeric paths).
|
|
18
|
+
if parsed.tzinfo is None:
|
|
19
|
+
parsed = parsed.replace(tzinfo=timezone.utc)
|
|
20
|
+
return parsed
|
|
16
21
|
elif isinstance(dt, int) or isinstance(dt, float):
|
|
17
22
|
return datetime.fromtimestamp(dt, tz=timezone.utc)
|
|
18
23
|
else:
|
|
@@ -12,7 +12,6 @@ from blockapi.v2.api.ethplorer import EthplorerApi
|
|
|
12
12
|
from blockapi.v2.api.haskoin import HaskoinApi
|
|
13
13
|
from blockapi.v2.api.litecoinspace import LitecoinSpaceApi
|
|
14
14
|
from blockapi.v2.api.optimistic_etherscan import OptimismEtherscanApi
|
|
15
|
-
from blockapi.v2.api.perpetual import PerpetualApi, perp_contract_address
|
|
16
15
|
from blockapi.v2.api.solana import SolanaApi, SolscanApi
|
|
17
16
|
from blockapi.v2.api.subscan import KusamaSubscanApi, PolkadotSubscanApi, SubscanApi
|
|
18
17
|
from blockapi.v2.api.terra import TerraApi
|
|
@@ -243,6 +243,9 @@ class DebankProtocolCache:
|
|
|
243
243
|
def __init__(self, timeout: int = 3600):
|
|
244
244
|
self._timeout: int = timeout
|
|
245
245
|
self._data: Dict[str, Protocol] = {}
|
|
246
|
+
# Naive local time on purpose: _timelimit is only ever compared against
|
|
247
|
+
# other datetime.now() values here (cache TTL), never mixed with the
|
|
248
|
+
# tz-aware datetimes used elsewhere, so there is no naive/aware hazard.
|
|
246
249
|
self._timelimit = datetime.now()
|
|
247
250
|
|
|
248
251
|
def invalidate(self):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from typing import Optional, Dict, Generator, Tuple
|
|
3
3
|
from enum import Enum
|
|
4
|
-
from datetime import datetime
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
5
|
|
|
6
6
|
from blockapi.v2.base import BlockchainApi, INftParser, INftProvider, ISleepProvider
|
|
7
7
|
from blockapi.v2.coins import COIN_BTC
|
|
@@ -670,7 +670,7 @@ class UnisatApi(BlockchainApi, INftParser, INftProvider):
|
|
|
670
670
|
try:
|
|
671
671
|
timestamp_seconds = timestamp / 1000
|
|
672
672
|
formatted_time = datetime.fromtimestamp(
|
|
673
|
-
timestamp_seconds
|
|
673
|
+
timestamp_seconds, tz=timezone.utc
|
|
674
674
|
).isoformat()
|
|
675
675
|
except (ValueError, TypeError, OverflowError):
|
|
676
676
|
logger.warning(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import time
|
|
3
3
|
from abc import ABC
|
|
4
|
-
from datetime import datetime, timedelta
|
|
4
|
+
from datetime import datetime, timedelta, timezone
|
|
5
5
|
from typing import Dict, List, Optional
|
|
6
6
|
from urllib.parse import urljoin
|
|
7
7
|
|
|
@@ -107,7 +107,7 @@ class CustomizableBlockchainApi(ABC):
|
|
|
107
107
|
return FetchResult(
|
|
108
108
|
status_code=1,
|
|
109
109
|
errors=[str(connection_error)],
|
|
110
|
-
time=datetime.
|
|
110
|
+
time=datetime.now(timezone.utc),
|
|
111
111
|
)
|
|
112
112
|
|
|
113
113
|
self.sleep_provider.sleep(self.base_url, seconds=sleep_seconds)
|
|
@@ -155,7 +155,7 @@ class CustomizableBlockchainApi(ABC):
|
|
|
155
155
|
headers=dict(),
|
|
156
156
|
errors=[f'{type(ex).__name__}: {str(ex)}'],
|
|
157
157
|
extra=extra,
|
|
158
|
-
time=datetime.
|
|
158
|
+
time=datetime.now(timezone.utc),
|
|
159
159
|
)
|
|
160
160
|
|
|
161
161
|
time = self._get_response_time(response.headers)
|
|
@@ -236,7 +236,7 @@ class CustomizableBlockchainApi(ABC):
|
|
|
236
236
|
return parse_dt(date_str)
|
|
237
237
|
|
|
238
238
|
if age_str := headers.get('age'):
|
|
239
|
-
return datetime.
|
|
239
|
+
return datetime.now(timezone.utc) - timedelta(seconds=int(age_str))
|
|
240
240
|
|
|
241
241
|
return None
|
|
242
242
|
|
|
@@ -431,15 +431,6 @@ COIN_DOGE = Coin(
|
|
|
431
431
|
info=CoinInfo(coingecko_id=CoingeckoId.DOGECOIN),
|
|
432
432
|
)
|
|
433
433
|
|
|
434
|
-
COIN_SNX = Coin(
|
|
435
|
-
symbol='SNX',
|
|
436
|
-
name='Synthetix',
|
|
437
|
-
decimals=18,
|
|
438
|
-
address='0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f',
|
|
439
|
-
blockchain=Blockchain.ETHEREUM,
|
|
440
|
-
info=CoinInfo(coingecko_id=CoingeckoId.SYNTHETIX),
|
|
441
|
-
)
|
|
442
|
-
|
|
443
434
|
|
|
444
435
|
COIN_CANTO = Coin(
|
|
445
436
|
symbol='CANTO',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from datetime import datetime
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
3
|
from decimal import Decimal
|
|
4
4
|
from enum import Enum
|
|
5
5
|
from typing import Dict, List, Literal, Optional, Union
|
|
@@ -473,7 +473,6 @@ class CoingeckoId(str, Enum):
|
|
|
473
473
|
SOLANA = 'solana'
|
|
474
474
|
SONGBIRD = 'songbird'
|
|
475
475
|
SUI = 'sui'
|
|
476
|
-
SYNTHETIX = 'havven'
|
|
477
476
|
TELOS = 'telos'
|
|
478
477
|
USDC = 'usd-coin'
|
|
479
478
|
WANCHAIN = 'wanchain'
|
|
@@ -864,7 +863,9 @@ class NftOffer:
|
|
|
864
863
|
contract=contract,
|
|
865
864
|
blockchain=blockchain,
|
|
866
865
|
offerer=offerer,
|
|
867
|
-
start_time=
|
|
866
|
+
start_time=(
|
|
867
|
+
parse_dt(start_time) if start_time else datetime.now(timezone.utc)
|
|
868
|
+
),
|
|
868
869
|
end_time=parse_dt(end_time) if end_time else None,
|
|
869
870
|
offer_coin=offer_coin,
|
|
870
871
|
offer_contract=offer_contract.lower() if offer_contract else None,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blockapi
|
|
3
|
-
Version: 2.10.
|
|
3
|
+
Version: 2.10.4
|
|
4
4
|
Summary: BlockAPI library
|
|
5
5
|
Home-page: https://github.com/crypkit/blockapi
|
|
6
6
|
Author: Devmons s.r.o.
|
|
@@ -9,18 +9,15 @@ Description-Content-Type: text/markdown
|
|
|
9
9
|
License-File: LICENSE.md
|
|
10
10
|
Requires-Dist: requests<3.0,>=2.28
|
|
11
11
|
Requires-Dist: python-dateutil>=2.8.0
|
|
12
|
+
Requires-Dist: cytoolz>=0.12.0
|
|
13
|
+
Requires-Dist: eth-utils>=2.0.0
|
|
12
14
|
Requires-Dist: coinaddrng==1.1.1
|
|
13
|
-
Requires-Dist: web3<8.0.0,>=5.2.2
|
|
14
|
-
Requires-Dist: bs4>=0.0.1
|
|
15
|
-
Requires-Dist: lxml>=4.4.1
|
|
16
15
|
Requires-Dist: pydantic>=1.10.2
|
|
17
|
-
Requires-Dist: marko<2.0.0,>=1.3.0
|
|
18
16
|
Requires-Dist: fake_useragent>=1.1.3
|
|
19
17
|
Requires-Dist: pytest
|
|
20
18
|
Requires-Dist: pytest-vcr
|
|
21
19
|
Requires-Dist: requests_mock>=1.9.3
|
|
22
20
|
Requires-Dist: attrs<23.0.0,>=17.4.0
|
|
23
|
-
Requires-Dist: solders>=0.22.0
|
|
24
21
|
Requires-Dist: base58>=2.1.0
|
|
25
22
|
Requires-Dist: aiohttp<3.14
|
|
26
23
|
Dynamic: author
|
|
@@ -51,10 +51,6 @@ blockapi/test/v2/api/nft/test_magic_eden.py
|
|
|
51
51
|
blockapi/test/v2/api/nft/test_opensea.py
|
|
52
52
|
blockapi/test/v2/api/nft/test_simple_hash.py
|
|
53
53
|
blockapi/test/v2/api/nft/test_unisat.py
|
|
54
|
-
blockapi/test/v2/api/perpetual/__init__.py
|
|
55
|
-
blockapi/test/v2/api/perpetual/test_perpetual.py
|
|
56
|
-
blockapi/test/v2/api/synthetix/__init__.py
|
|
57
|
-
blockapi/test/v2/api/synthetix/test_synthetix.py
|
|
58
54
|
blockapi/utils/__init__.py
|
|
59
55
|
blockapi/utils/address.py
|
|
60
56
|
blockapi/utils/datetime.py
|
|
@@ -83,7 +79,6 @@ blockapi/v2/api/subscan.py
|
|
|
83
79
|
blockapi/v2/api/sui.py
|
|
84
80
|
blockapi/v2/api/terra.py
|
|
85
81
|
blockapi/v2/api/trezor.py
|
|
86
|
-
blockapi/v2/api/web3_utils.py
|
|
87
82
|
blockapi/v2/api/covalenth/__init__.py
|
|
88
83
|
blockapi/v2/api/covalenth/arbitrum.py
|
|
89
84
|
blockapi/v2/api/covalenth/astar.py
|
|
@@ -104,10 +99,4 @@ blockapi/v2/api/nft/__init__.py
|
|
|
104
99
|
blockapi/v2/api/nft/magic_eden.py
|
|
105
100
|
blockapi/v2/api/nft/opensea.py
|
|
106
101
|
blockapi/v2/api/nft/simple_hash.py
|
|
107
|
-
blockapi/v2/api/nft/unisat.py
|
|
108
|
-
blockapi/v2/api/perpetual/__init__.py
|
|
109
|
-
blockapi/v2/api/perpetual/perp_abi.py
|
|
110
|
-
blockapi/v2/api/perpetual/perpetual.py
|
|
111
|
-
blockapi/v2/api/synthetix/__init__.py
|
|
112
|
-
blockapi/v2/api/synthetix/synthetix.py
|
|
113
|
-
blockapi/v2/api/synthetix/synthetix_abi.py
|
|
102
|
+
blockapi/v2/api/nft/unisat.py
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
requests<3.0,>=2.28
|
|
2
2
|
python-dateutil>=2.8.0
|
|
3
|
+
cytoolz>=0.12.0
|
|
4
|
+
eth-utils>=2.0.0
|
|
3
5
|
coinaddrng==1.1.1
|
|
4
|
-
web3<8.0.0,>=5.2.2
|
|
5
|
-
bs4>=0.0.1
|
|
6
|
-
lxml>=4.4.1
|
|
7
6
|
pydantic>=1.10.2
|
|
8
|
-
marko<2.0.0,>=1.3.0
|
|
9
7
|
fake_useragent>=1.1.3
|
|
10
8
|
pytest
|
|
11
9
|
pytest-vcr
|
|
12
10
|
requests_mock>=1.9.3
|
|
13
11
|
attrs<23.0.0,>=17.4.0
|
|
14
|
-
solders>=0.22.0
|
|
15
12
|
base58>=2.1.0
|
|
16
13
|
aiohttp<3.14
|
|
@@ -6,7 +6,7 @@ with open("README.md", "r") as f:
|
|
|
6
6
|
|
|
7
7
|
PACKAGES = find_packages(where='.')
|
|
8
8
|
|
|
9
|
-
__version__ = "2.10.
|
|
9
|
+
__version__ = "2.10.4"
|
|
10
10
|
|
|
11
11
|
setuptools.setup(
|
|
12
12
|
name='blockapi',
|
|
@@ -20,18 +20,15 @@ setuptools.setup(
|
|
|
20
20
|
install_requires=[
|
|
21
21
|
'requests>=2.28,<3.0',
|
|
22
22
|
'python-dateutil>=2.8.0',
|
|
23
|
+
'cytoolz>=0.12.0',
|
|
24
|
+
'eth-utils>=2.0.0',
|
|
23
25
|
'coinaddrng==1.1.1',
|
|
24
|
-
'web3>=5.2.2,<8.0.0',
|
|
25
|
-
'bs4>=0.0.1',
|
|
26
|
-
'lxml>=4.4.1',
|
|
27
26
|
'pydantic>=1.10.2',
|
|
28
|
-
'marko>=1.3.0,<2.0.0',
|
|
29
27
|
'fake_useragent>=1.1.3',
|
|
30
28
|
'pytest',
|
|
31
29
|
'pytest-vcr',
|
|
32
30
|
'requests_mock>=1.9.3',
|
|
33
31
|
'attrs>=17.4.0,<23.0.0',
|
|
34
|
-
'solders>=0.22.0',
|
|
35
32
|
'base58>=2.1.0',
|
|
36
33
|
# vcrpy incompatible with 3.14, remove once vcrpy>8.1.1 is out
|
|
37
34
|
'aiohttp<3.14',
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
import pytest
|
|
4
|
-
from _decimal import Decimal
|
|
5
|
-
|
|
6
|
-
from blockapi.v2.api import PerpetualApi, perp_contract_address
|
|
7
|
-
from blockapi.v2.base import ApiException
|
|
8
|
-
from blockapi.v2.models import FetchResult
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@pytest.fixture
|
|
12
|
-
def perp_api():
|
|
13
|
-
return PerpetualApi('http://localhost:2048/')
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
test_address = '0x134089B387E22f52b1e06CC80d9a5F622032EF74'
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@pytest.mark.skip(
|
|
20
|
-
reason='metadata.perp.exchange/production.json returns 404 — upstream endpoint is offline'
|
|
21
|
-
)
|
|
22
|
-
def test_perp_contract_address():
|
|
23
|
-
contract = perp_contract_address('PERP')
|
|
24
|
-
assert contract == '0xbC396689893D065F41bc2C6EcbeE5e0085233447'
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@pytest.mark.skip(
|
|
28
|
-
reason='metadata.perp.exchange/production.json returns 404 — upstream endpoint is offline'
|
|
29
|
-
)
|
|
30
|
-
def test_perp_invalid_contract_raises():
|
|
31
|
-
with pytest.raises(ValueError, match='Invalid contract name.'):
|
|
32
|
-
perp_contract_address("abc")
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def test_perp_has_coin(perp_api):
|
|
36
|
-
assert perp_api.coin.symbol == 'PERP'
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def filter_infura_key(request):
|
|
40
|
-
if 'infura.io' in request.host:
|
|
41
|
-
request.uri = 'https://mainnet.infura.io/v3/API_KEY_FILTERED'
|
|
42
|
-
return request
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
@pytest.mark.integration
|
|
46
|
-
@pytest.mark.skip(
|
|
47
|
-
reason='metadata.perp.exchange/production.json returns 404 — upstream endpoint is offline'
|
|
48
|
-
)
|
|
49
|
-
def test_fetch():
|
|
50
|
-
key = os.environ.get('INFURA_API_KEY')
|
|
51
|
-
api = PerpetualApi(f'https://mainnet.infura.io/v3/{key}')
|
|
52
|
-
raw = api.fetch_balances(test_address)
|
|
53
|
-
assert raw.data
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
@pytest.mark.integration
|
|
57
|
-
@pytest.mark.skip(
|
|
58
|
-
reason='metadata.perp.exchange/production.json returns 404 — upstream endpoint is offline'
|
|
59
|
-
)
|
|
60
|
-
def test_fetch_error():
|
|
61
|
-
api = PerpetualApi(f'https://mainnet.infura.io/v3/no-key')
|
|
62
|
-
raw = api.fetch_balances(test_address)
|
|
63
|
-
assert raw.status_code == 401
|
|
64
|
-
assert (
|
|
65
|
-
raw.errors[0]
|
|
66
|
-
== '401 Client Error: Unauthorized for url: https://mainnet.infura.io/v3/no-key'
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
@pytest.mark.skip(
|
|
71
|
-
reason='metadata.perp.exchange/production.json returns 404 — upstream endpoint is offline'
|
|
72
|
-
)
|
|
73
|
-
def test_fetch_error_raises_from_get_balances():
|
|
74
|
-
api = PerpetualApi(f'https://mainnet.infura.io/v3/no-key')
|
|
75
|
-
with pytest.raises(ApiException) as exc:
|
|
76
|
-
api.get_balance(test_address)
|
|
77
|
-
|
|
78
|
-
assert exc.match('401 Client Error: Unauthorized for url')
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def test_parse(perp_api):
|
|
82
|
-
raw = FetchResult(
|
|
83
|
-
status_code=200,
|
|
84
|
-
data=dict(
|
|
85
|
-
staking_claimable='1.10',
|
|
86
|
-
vesting_claimable='2.02',
|
|
87
|
-
vesting_locked='3.30',
|
|
88
|
-
),
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
parsed = perp_api.parse_balances(raw)
|
|
92
|
-
|
|
93
|
-
assert parsed.data[0].balance == Decimal('3.12')
|
|
94
|
-
assert parsed.data[1].balance == Decimal('3.30')
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
from decimal import Decimal
|
|
2
|
-
from unittest.mock import patch
|
|
3
|
-
|
|
4
|
-
import pytest
|
|
5
|
-
|
|
6
|
-
from blockapi.test.v2.api.conftest import read_file
|
|
7
|
-
from blockapi.v2.api.synthetix import (
|
|
8
|
-
SynthetixMainnetApi,
|
|
9
|
-
SynthetixOptimismApi,
|
|
10
|
-
snx_contract_address,
|
|
11
|
-
)
|
|
12
|
-
from blockapi.v2.models import AssetType, BalanceItem, Blockchain, Coin
|
|
13
|
-
|
|
14
|
-
test_address = '0xE2e4F2A725E42D0F0EF6291F46c430F963482001'
|
|
15
|
-
contract_name = 'Synthetix'
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def mock_redirect(requests_mock, source, target, text):
|
|
19
|
-
requests_mock.get(source, status_code=302, headers={'location': target})
|
|
20
|
-
requests_mock.get(target, text=text)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def test_snx_contract_address_mainnet(requests_mock):
|
|
24
|
-
mock_redirect(
|
|
25
|
-
requests_mock,
|
|
26
|
-
source='https://contracts.synthetix.io/Synthetix',
|
|
27
|
-
target='https://etherscan.io/address/0x08F30Ecf2C15A783083ab9D5b9211c22388d0564',
|
|
28
|
-
text='',
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
assert (
|
|
32
|
-
snx_contract_address(contract_name)
|
|
33
|
-
== '0x08F30Ecf2C15A783083ab9D5b9211c22388d0564'
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def test_snx_contract_address_optimism(requests_mock):
|
|
38
|
-
text = read_file('synthetix/data/contracts.md')
|
|
39
|
-
requests_mock.get(
|
|
40
|
-
'https://raw.githubusercontent.com/Synthetixio/synthetix-docs/master/content/addresses.md',
|
|
41
|
-
text=text,
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
assert (
|
|
45
|
-
snx_contract_address(contract_name, 'optimism')
|
|
46
|
-
== '0x49B35BE7D96888C02F342552aB218d859599aCeb'
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def test_invalid_contract_raises(requests_mock):
|
|
51
|
-
requests_mock.get('https://contracts.synthetix.io/abc', status_code=404)
|
|
52
|
-
|
|
53
|
-
with pytest.raises(ValueError, match='Contract abc not found'):
|
|
54
|
-
snx_contract_address('abc')
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def test_invalid_contract_optimism_raises(requests_mock):
|
|
58
|
-
text = read_file('synthetix/data/contracts.md')
|
|
59
|
-
requests_mock.get(
|
|
60
|
-
'https://raw.githubusercontent.com/Synthetixio/synthetix-docs/master/content/addresses.md',
|
|
61
|
-
text=text,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
with pytest.raises(ValueError, match='Contract abc not found'):
|
|
65
|
-
snx_contract_address('abc', 'optimism')
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def test_create_with_custom_api():
|
|
69
|
-
api = SynthetixMainnetApi(api_url='http://localhost:1234/')
|
|
70
|
-
assert api.w3.provider.endpoint_uri == 'http://localhost:1234/'
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def test_create_with_custom_optimism_api():
|
|
74
|
-
api = SynthetixOptimismApi(api_url='http://localhost:1234/')
|
|
75
|
-
assert api.w3.provider.endpoint_uri == 'http://localhost:1234/'
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
@pytest.mark.skip("For some reason VCR cassette doesn't work properly")
|
|
79
|
-
@pytest.mark.vcr()
|
|
80
|
-
def test_synthetix_optimism_api():
|
|
81
|
-
api = SynthetixOptimismApi(api_url='https://mainnet.optimism.io/')
|
|
82
|
-
balances = api.get_balance(test_address)
|
|
83
|
-
|
|
84
|
-
assert balances == [
|
|
85
|
-
BalanceItem(
|
|
86
|
-
balance=Decimal('376576.311381339269627458'),
|
|
87
|
-
balance_raw=Decimal('376576311381339269627458'),
|
|
88
|
-
raw={},
|
|
89
|
-
coin=Coin(
|
|
90
|
-
symbol='sUSD',
|
|
91
|
-
name='sUSD',
|
|
92
|
-
decimals=18,
|
|
93
|
-
blockchain=Blockchain.OPTIMISM,
|
|
94
|
-
address='0x8c6f28f2F1A3C87F0f938b96d27520d9751ec8d9',
|
|
95
|
-
standards=None,
|
|
96
|
-
protocol_id=None,
|
|
97
|
-
info=None,
|
|
98
|
-
),
|
|
99
|
-
asset_type=AssetType.DEBT,
|
|
100
|
-
),
|
|
101
|
-
BalanceItem(
|
|
102
|
-
balance=Decimal('528051.112125559541484602'),
|
|
103
|
-
balance_raw=Decimal('528051112125559541484602'),
|
|
104
|
-
raw={},
|
|
105
|
-
coin=Coin(
|
|
106
|
-
symbol='SNX',
|
|
107
|
-
name='SNX',
|
|
108
|
-
decimals=18,
|
|
109
|
-
blockchain=Blockchain.OPTIMISM,
|
|
110
|
-
address='0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4',
|
|
111
|
-
standards=None,
|
|
112
|
-
protocol_id=None,
|
|
113
|
-
info=None,
|
|
114
|
-
),
|
|
115
|
-
asset_type=AssetType.STAKED,
|
|
116
|
-
),
|
|
117
|
-
BalanceItem(
|
|
118
|
-
balance=Decimal('188153.171065910534455462'),
|
|
119
|
-
balance_raw=Decimal('188153171065910534455462'),
|
|
120
|
-
raw={},
|
|
121
|
-
coin=Coin(
|
|
122
|
-
symbol='SNX',
|
|
123
|
-
name='SNX',
|
|
124
|
-
decimals=18,
|
|
125
|
-
blockchain=Blockchain.OPTIMISM,
|
|
126
|
-
address='0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4',
|
|
127
|
-
standards=None,
|
|
128
|
-
protocol_id=None,
|
|
129
|
-
info=None,
|
|
130
|
-
),
|
|
131
|
-
asset_type=AssetType.VESTING,
|
|
132
|
-
),
|
|
133
|
-
]
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
@pytest.fixture()
|
|
137
|
-
def mocked_get_synth_contract():
|
|
138
|
-
with patch(
|
|
139
|
-
'blockapi.v2.api.synthetix.synthetix.SynthetixApi._get_synth_contract'
|
|
140
|
-
) as patched:
|
|
141
|
-
patched.return_value = '0x0000000000000000000000000000000000000000'
|
|
142
|
-
yield patched
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
def test_yield_balances_from_staking(mocked_get_synth_contract):
|
|
146
|
-
api = SynthetixMainnetApi(api_url='http://localhost:1234/')
|
|
147
|
-
staking = {
|
|
148
|
-
'transferable': Decimal(10),
|
|
149
|
-
'debt': Decimal(10),
|
|
150
|
-
'staked': Decimal(10),
|
|
151
|
-
'vesting': Decimal(8),
|
|
152
|
-
'collateral': Decimal(100),
|
|
153
|
-
'rewards': {
|
|
154
|
-
'exchange': Decimal(2),
|
|
155
|
-
'staking': Decimal(3),
|
|
156
|
-
},
|
|
157
|
-
'liquidation_reward': Decimal(3),
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
balances = list(api.yield_balances_from_staking(staking))
|
|
161
|
-
|
|
162
|
-
assert balances[2].asset_type == AssetType.STAKED
|
|
163
|
-
assert balances[2].balance_raw == Decimal(89)
|
|
164
|
-
|
|
165
|
-
assert balances[3].asset_type == AssetType.PRICED_VESTING
|
|
166
|
-
assert balances[3].balance_raw == Decimal(8)
|
|
File without changes
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from blockapi.v2.api.perpetual.perpetual import PerpetualApi, perp_contract_address
|