blockapi 2.11.2__tar.gz → 2.11.3__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.11.2 → blockapi-2.11.3}/PKG-INFO +1 -1
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_solana.py +148 -7
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/solana.py +46 -17
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi.egg-info/PKG-INFO +1 -1
- {blockapi-2.11.2 → blockapi-2.11.3}/setup.py +1 -1
- {blockapi-2.11.2 → blockapi-2.11.3}/LICENSE.md +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/README.md +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/__init__.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/services.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/__init__.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/test_blockapi.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/test_num.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/test_random_user_agent.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/__init__.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/__init__.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/conftest.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/covalenth/__init__.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/covalenth/test_ethereum.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/fake_sleep_provider.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/nft/__init__.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/nft/test_magic_eden.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/nft/test_opensea.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/nft/test_simple_hash.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/nft/test_unisat.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_bitaps_ltc.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_blockchain_info.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_blockchainos.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_blockchair_btc.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_blockchair_doge.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_blockchair_ltc.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_cosmos.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_ethplorer.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_haskoin.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_litecoinspace.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_multisources.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_optimistic_etherscan.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_subscan_polkadot.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_sui.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_terra.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_trezor_btc.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/api/test_trezor_zec.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/test_base.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/test_blockchain_api.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/test_blockchain_mapping.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/test_data.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/test_enumerate_classes.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/test_generic.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test/v2/test_models.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/test_data.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/utils/__init__.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/utils/address.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/utils/datetime.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/utils/num.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/utils/user_agent.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/__init__.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/__init__.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/bitaps.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/blockchain_info.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/blockchainos.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/blockchair.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/cosmos.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/__init__.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/arbitrum.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/astar.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/avalanche.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/axie.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/base.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/binance_smart_chain.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/ethereum.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/fantom.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/heco.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/iotex.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/klaytn.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/moonbeam.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/palm.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/polygon.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/covalenth/rsk.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/debank.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/debank_maps.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/ethplorer.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/haskoin.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/litecoinspace.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/nft/__init__.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/nft/magic_eden.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/nft/opensea.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/nft/simple_hash.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/nft/unisat.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/optimistic_etherscan.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/subscan.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/sui.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/terra.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/api/trezor.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/base.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/blockchain_mapping.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/coin_mapping.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/coins.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi/v2/models.py +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi.egg-info/SOURCES.txt +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi.egg-info/dependency_links.txt +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi.egg-info/requires.txt +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/blockapi.egg-info/top_level.txt +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/pyproject.toml +0 -0
- {blockapi-2.11.2 → blockapi-2.11.3}/setup.cfg +0 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import json
|
|
1
2
|
from decimal import Decimal
|
|
2
|
-
from unittest.mock import patch
|
|
3
|
+
from unittest.mock import call, patch
|
|
3
4
|
|
|
4
5
|
import pytest
|
|
5
6
|
from requests_mock import ANY, Mocker
|
|
6
7
|
|
|
7
8
|
from blockapi.test.v2.api.conftest import read_file
|
|
8
9
|
from blockapi.v2.api import SolanaApi, SolscanApi
|
|
10
|
+
from blockapi.v2.base import ApiException
|
|
9
11
|
from blockapi.v2.models import (
|
|
10
12
|
AssetType,
|
|
11
13
|
BalanceItem,
|
|
@@ -74,14 +76,26 @@ def test_use_base_url():
|
|
|
74
76
|
assert api.base_url == 'https://api.mainnet-beta.solana.com/'
|
|
75
77
|
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
@pytest.mark.parametrize(
|
|
80
|
+
('rpc_url', 'uses_v2_staking'),
|
|
81
|
+
[
|
|
82
|
+
('https://mainnet.helius-rpc.com/', True),
|
|
83
|
+
('https://proxy/solana/', False),
|
|
84
|
+
],
|
|
85
|
+
)
|
|
86
|
+
def test_get_balance_supports_helius_and_legacy_staking_responses(
|
|
78
87
|
sol_balance_response,
|
|
79
88
|
token_accounts_response,
|
|
80
89
|
das_asset_batch_response,
|
|
81
90
|
staked_solana_response,
|
|
91
|
+
rpc_url,
|
|
92
|
+
uses_v2_staking,
|
|
82
93
|
):
|
|
83
94
|
test_addr = '5PjMxaijeVVQtuEzxK2NxyJeWwUbpTsi2uXuZ653WoHu'
|
|
84
95
|
empty_token_accounts = '{"jsonrpc":"2.0","result":{"context":{"apiVersion":"1.17.34","slot":268207149},"value":[]},"id":1}'
|
|
96
|
+
staking_response = json.loads(staked_solana_response)
|
|
97
|
+
if not uses_v2_staking:
|
|
98
|
+
staking_response['result'] = staking_response['result']['accounts']
|
|
85
99
|
|
|
86
100
|
iterator = iter(
|
|
87
101
|
[
|
|
@@ -89,19 +103,29 @@ def test_use_base_url_in_post(
|
|
|
89
103
|
token_accounts_response,
|
|
90
104
|
empty_token_accounts,
|
|
91
105
|
das_asset_batch_response,
|
|
92
|
-
|
|
106
|
+
json.dumps(staking_response),
|
|
93
107
|
]
|
|
94
108
|
)
|
|
95
109
|
|
|
96
110
|
def get_text(*args, **kwargs):
|
|
97
|
-
assert args[0].url ==
|
|
111
|
+
assert args[0].url == rpc_url
|
|
98
112
|
data = next(iterator)
|
|
99
113
|
return data
|
|
100
114
|
|
|
101
115
|
with Mocker() as m:
|
|
102
|
-
m.post(ANY, text=get_text)
|
|
103
|
-
api = SolanaApi(base_url=
|
|
104
|
-
api.get_balance(test_addr)
|
|
116
|
+
m.post(ANY, text=get_text)
|
|
117
|
+
api = SolanaApi(base_url=rpc_url)
|
|
118
|
+
balances = api.get_balance(test_addr)
|
|
119
|
+
|
|
120
|
+
staking_balances = {
|
|
121
|
+
balance.asset_type: balance.balance_raw
|
|
122
|
+
for balance in balances
|
|
123
|
+
if balance.asset_type in {AssetType.STAKED, AssetType.LOCKED}
|
|
124
|
+
}
|
|
125
|
+
assert staking_balances == {
|
|
126
|
+
AssetType.STAKED: Decimal('179062913955311'),
|
|
127
|
+
AssetType.LOCKED: Decimal('424045085255'),
|
|
128
|
+
}
|
|
105
129
|
|
|
106
130
|
|
|
107
131
|
def test_build_coin_from_das_asset():
|
|
@@ -237,6 +261,123 @@ def test_parse_staked_balance_skips_undelegated():
|
|
|
237
261
|
assert result.asset_type == AssetType.STAKED
|
|
238
262
|
|
|
239
263
|
|
|
264
|
+
def test_fetch_staked_sol_uses_v2_pagination():
|
|
265
|
+
api = SolanaApi(base_url='https://mainnet.helius-rpc.com/')
|
|
266
|
+
address = '5PjMxaijeVVQtuEzxK2NxyJeWwUbpTsi2uXuZ653WoHu'
|
|
267
|
+
first_account = {'pubkey': 'first'}
|
|
268
|
+
second_account = {'pubkey': 'second'}
|
|
269
|
+
|
|
270
|
+
with patch.object(
|
|
271
|
+
api,
|
|
272
|
+
'_request',
|
|
273
|
+
side_effect=[
|
|
274
|
+
{
|
|
275
|
+
'jsonrpc': '2.0',
|
|
276
|
+
'id': 1,
|
|
277
|
+
'result': {
|
|
278
|
+
'accounts': [first_account],
|
|
279
|
+
'paginationKey': 'next-page',
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
'jsonrpc': '2.0',
|
|
284
|
+
'id': 2,
|
|
285
|
+
'result': {
|
|
286
|
+
'accounts': [],
|
|
287
|
+
'paginationKey': 'last-page',
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
'jsonrpc': '2.0',
|
|
292
|
+
'id': 3,
|
|
293
|
+
'result': {
|
|
294
|
+
'accounts': [second_account],
|
|
295
|
+
'paginationKey': None,
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
) as request:
|
|
300
|
+
response = api._fetch_staked_sol(address)
|
|
301
|
+
|
|
302
|
+
config = {
|
|
303
|
+
'filters': [
|
|
304
|
+
{
|
|
305
|
+
'memcmp': {
|
|
306
|
+
'offset': api.STAKE_AUTHORITY_OFFSET,
|
|
307
|
+
'bytes': address,
|
|
308
|
+
'encoding': 'base58',
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
],
|
|
312
|
+
'encoding': 'jsonParsed',
|
|
313
|
+
'commitment': 'finalized',
|
|
314
|
+
'limit': api.HELIUS_PROGRAM_ACCOUNTS_PAGE_SIZE,
|
|
315
|
+
}
|
|
316
|
+
assert request.call_args_list == [
|
|
317
|
+
call(
|
|
318
|
+
method='getProgramAccountsV2',
|
|
319
|
+
params=[api.STAKE_PROGRAM_ID, config],
|
|
320
|
+
),
|
|
321
|
+
call(
|
|
322
|
+
method='getProgramAccountsV2',
|
|
323
|
+
params=[
|
|
324
|
+
api.STAKE_PROGRAM_ID,
|
|
325
|
+
{**config, 'paginationKey': 'next-page'},
|
|
326
|
+
],
|
|
327
|
+
),
|
|
328
|
+
call(
|
|
329
|
+
method='getProgramAccountsV2',
|
|
330
|
+
params=[
|
|
331
|
+
api.STAKE_PROGRAM_ID,
|
|
332
|
+
{**config, 'paginationKey': 'last-page'},
|
|
333
|
+
],
|
|
334
|
+
),
|
|
335
|
+
]
|
|
336
|
+
assert response == {
|
|
337
|
+
'jsonrpc': '2.0',
|
|
338
|
+
'id': 3,
|
|
339
|
+
'result': [first_account, second_account],
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def test_fetch_staked_sol_rejects_repeated_pagination_key():
|
|
344
|
+
api = SolanaApi(base_url='https://mainnet.helius-rpc.com/')
|
|
345
|
+
repeated_page = {
|
|
346
|
+
'result': {
|
|
347
|
+
'accounts': [],
|
|
348
|
+
'paginationKey': 'same-page',
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
terminal_page = {
|
|
352
|
+
'result': {
|
|
353
|
+
'accounts': [],
|
|
354
|
+
'paginationKey': None,
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
with patch.object(
|
|
359
|
+
api,
|
|
360
|
+
'_request',
|
|
361
|
+
side_effect=[repeated_page, repeated_page, terminal_page],
|
|
362
|
+
) as request:
|
|
363
|
+
with pytest.raises(ApiException, match='repeated pagination key'):
|
|
364
|
+
api._fetch_staked_sol('address')
|
|
365
|
+
|
|
366
|
+
assert request.call_count == 2
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def test_fetch_staked_sol_uses_legacy_method_for_non_helius_rpc():
|
|
370
|
+
api = SolanaApi()
|
|
371
|
+
|
|
372
|
+
with patch.object(api, '_request', return_value={'result': []}) as request:
|
|
373
|
+
response = api._fetch_staked_sol('address')
|
|
374
|
+
|
|
375
|
+
request.assert_called_once()
|
|
376
|
+
assert request.call_args.kwargs['method'] == 'getProgramAccounts'
|
|
377
|
+
assert 'limit' not in request.call_args.kwargs['params'][1]
|
|
378
|
+
assert response == {'result': []}
|
|
379
|
+
|
|
380
|
+
|
|
240
381
|
def test_das_cache_stores_sentinel_for_unknown_mint():
|
|
241
382
|
api = SolanaApi()
|
|
242
383
|
unknown_mint = 'UnknownMint111111111111111111111111111111111'
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
3
|
from typing import Optional, Union
|
|
4
|
+
from urllib.parse import urlparse
|
|
4
5
|
|
|
5
6
|
from cytoolz import reduceby
|
|
6
7
|
from requests import Response
|
|
@@ -79,6 +80,8 @@ class SolanaApi(CustomizableBlockchainApi, BalanceMixin):
|
|
|
79
80
|
TOKEN_2022_PROGRAM_ID = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'
|
|
80
81
|
STAKE_PROGRAM_ID = 'Stake11111111111111111111111111111111111111'
|
|
81
82
|
STAKE_AUTHORITY_OFFSET = 44
|
|
83
|
+
HELIUS_RPC_DOMAIN = 'helius-rpc.com'
|
|
84
|
+
HELIUS_PROGRAM_ACCOUNTS_PAGE_SIZE = 5000
|
|
82
85
|
DAS_BATCH_SIZE = 1000
|
|
83
86
|
_JSONRPC_INVALID_PARAMS = -32602
|
|
84
87
|
|
|
@@ -314,25 +317,51 @@ class SolanaApi(CustomizableBlockchainApi, BalanceMixin):
|
|
|
314
317
|
|
|
315
318
|
def _fetch_staked_sol(self, address: str) -> dict:
|
|
316
319
|
"""Fetch staked SOL accounts for a given address."""
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
params=[
|
|
320
|
-
self.STAKE_PROGRAM_ID,
|
|
320
|
+
config = {
|
|
321
|
+
'filters': [
|
|
321
322
|
{
|
|
322
|
-
'
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
],
|
|
331
|
-
'encoding': 'jsonParsed',
|
|
332
|
-
'commitment': 'finalized',
|
|
333
|
-
},
|
|
323
|
+
'memcmp': {
|
|
324
|
+
'offset': self.STAKE_AUTHORITY_OFFSET,
|
|
325
|
+
'bytes': address,
|
|
326
|
+
'encoding': 'base58',
|
|
327
|
+
}
|
|
328
|
+
}
|
|
334
329
|
],
|
|
330
|
+
'encoding': 'jsonParsed',
|
|
331
|
+
'commitment': 'finalized',
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
hostname = urlparse(self.base_url).hostname or ''
|
|
335
|
+
is_helius_rpc = hostname == self.HELIUS_RPC_DOMAIN or hostname.endswith(
|
|
336
|
+
f'.{self.HELIUS_RPC_DOMAIN}'
|
|
335
337
|
)
|
|
338
|
+
if not is_helius_rpc:
|
|
339
|
+
return self._request(
|
|
340
|
+
method='getProgramAccounts',
|
|
341
|
+
params=[self.STAKE_PROGRAM_ID, config],
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
config['limit'] = self.HELIUS_PROGRAM_ACCOUNTS_PAGE_SIZE
|
|
345
|
+
accounts = []
|
|
346
|
+
seen_pagination_keys = set()
|
|
347
|
+
|
|
348
|
+
while True:
|
|
349
|
+
response = self._request(
|
|
350
|
+
method='getProgramAccountsV2',
|
|
351
|
+
params=[self.STAKE_PROGRAM_ID, config],
|
|
352
|
+
)
|
|
353
|
+
page = response['result']
|
|
354
|
+
accounts.extend(page['accounts'])
|
|
355
|
+
|
|
356
|
+
pagination_key = page.get('paginationKey')
|
|
357
|
+
if pagination_key is None:
|
|
358
|
+
response['result'] = accounts
|
|
359
|
+
return response
|
|
360
|
+
if pagination_key in seen_pagination_keys:
|
|
361
|
+
raise ApiException('Solana RPC returned a repeated pagination key')
|
|
362
|
+
|
|
363
|
+
seen_pagination_keys.add(pagination_key)
|
|
364
|
+
config = {**config, 'paginationKey': pagination_key}
|
|
336
365
|
|
|
337
366
|
# ── Balance parsing ────────────────────────────────────────
|
|
338
367
|
|
|
@@ -373,7 +402,7 @@ class SolanaApi(CustomizableBlockchainApi, BalanceMixin):
|
|
|
373
402
|
def _parse_rent_reserve(
|
|
374
403
|
self, staked_sol: BalanceItem, raw_staked_sol: dict
|
|
375
404
|
) -> BalanceItem:
|
|
376
|
-
"""Parse rent reserve from
|
|
405
|
+
"""Parse rent reserve from a program accounts response.
|
|
377
406
|
|
|
378
407
|
Uses result[].account.lamports already returned by _fetch_staked_sol,
|
|
379
408
|
avoiding a separate getMultipleAccounts call.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|