tonutils 2.0.1b5__tar.gz → 2.0.1b6__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.
- {tonutils-2.0.1b5/tonutils.egg-info → tonutils-2.0.1b6}/PKG-INFO +1 -1
- tonutils-2.0.1b6/tonutils/__meta__.py +1 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/__init__.py +10 -10
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/balancer.py +21 -24
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/client.py +21 -24
- tonutils-2.0.1b6/tonutils/clients/adnl/provider/config.py +48 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/base.py +17 -11
- tonutils-2.0.1b6/tonutils/clients/http/__init__.py +23 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/http/balancer.py +11 -11
- tonutils-2.0.1b6/tonutils/clients/http/clients/__init__.py +13 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/http/clients/chainstack.py +3 -3
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/http/clients/quicknode.py +2 -3
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/http/clients/tatum.py +3 -3
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/http/clients/tonapi.py +9 -10
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/http/clients/toncenter.py +50 -23
- {tonutils-2.0.1b5/tonutils/clients/http/providers → tonutils-2.0.1b6/tonutils/clients/http/provider}/__init__.py +4 -1
- {tonutils-2.0.1b5/tonutils/clients/http/providers → tonutils-2.0.1b6/tonutils/clients/http/provider}/base.py +71 -7
- {tonutils-2.0.1b5/tonutils/clients/http/providers/toncenter → tonutils-2.0.1b6/tonutils/clients/http/provider}/models.py +43 -1
- tonutils-2.0.1b5/tonutils/clients/http/providers/tonapi/provider.py → tonutils-2.0.1b6/tonutils/clients/http/provider/tonapi.py +8 -8
- tonutils-2.0.1b5/tonutils/clients/http/providers/toncenter/provider.py → tonutils-2.0.1b6/tonutils/clients/http/provider/toncenter.py +22 -14
- tonutils-2.0.1b6/tonutils/clients/limiter.py +117 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/protocol.py +2 -2
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/base.py +2 -3
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/messages.py +4 -8
- tonutils-2.0.1b6/tonutils/tonconnect/bridge/__init__.py +0 -0
- tonutils-2.0.1b6/tonutils/tonconnect/events.py +0 -0
- tonutils-2.0.1b6/tonutils/tonconnect/models/__init__.py +0 -0
- tonutils-2.0.1b6/tonutils/tonconnect/storage.py +0 -0
- tonutils-2.0.1b6/tonutils/tonconnect/tonconnect.py +0 -0
- tonutils-2.0.1b6/tonutils/tools/block_scanner/__init__.py +9 -0
- tonutils-2.0.1b6/tonutils/tools/block_scanner/events.py +72 -0
- tonutils-2.0.1b6/tonutils/tools/block_scanner/scanner.py +407 -0
- tonutils-2.0.1b6/tonutils/tools/block_scanner/storage.py +11 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/utils.py +0 -48
- {tonutils-2.0.1b5 → tonutils-2.0.1b6/tonutils.egg-info}/PKG-INFO +1 -1
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils.egg-info/SOURCES.txt +11 -13
- tonutils-2.0.1b5/tonutils/__meta__.py +0 -1
- tonutils-2.0.1b5/tonutils/clients/adnl/provider/config.py +0 -33
- tonutils-2.0.1b5/tonutils/clients/http/__init__.py +0 -23
- tonutils-2.0.1b5/tonutils/clients/http/clients/__init__.py +0 -13
- tonutils-2.0.1b5/tonutils/clients/http/providers/response.py +0 -85
- tonutils-2.0.1b5/tonutils/clients/http/providers/tonapi/__init__.py +0 -3
- tonutils-2.0.1b5/tonutils/clients/http/providers/tonapi/models.py +0 -47
- tonutils-2.0.1b5/tonutils/clients/http/providers/toncenter/__init__.py +0 -3
- tonutils-2.0.1b5/tonutils/clients/limiter.py +0 -115
- tonutils-2.0.1b5/tonutils/tools/block_scanner/__init__.py +0 -16
- tonutils-2.0.1b5/tonutils/tools/block_scanner/annotations.py +0 -23
- tonutils-2.0.1b5/tonutils/tools/block_scanner/dispatcher.py +0 -141
- tonutils-2.0.1b5/tonutils/tools/block_scanner/events.py +0 -31
- tonutils-2.0.1b5/tonutils/tools/block_scanner/scanner.py +0 -313
- tonutils-2.0.1b5/tonutils/tools/block_scanner/traversal.py +0 -97
- tonutils-2.0.1b5/tonutils/tools/block_scanner/where.py +0 -53
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/LICENSE +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/README.md +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/pyproject.toml +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/setup.cfg +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/cli.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/provider/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/provider/models.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/provider/provider.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/provider/transport.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/provider/workers/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/provider/workers/base.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/provider/workers/pinger.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/provider/workers/reader.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/provider/workers/updater.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/adnl/utils.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/clients/http/utils.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/base.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/codes.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/dns/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/dns/collection.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/dns/item.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/dns/methods.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/dns/tlb.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/jetton/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/jetton/master.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/jetton/methods.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/jetton/tlb.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/jetton/wallet.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/nft/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/nft/collection.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/nft/item.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/nft/methods.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/nft/tlb.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/opcodes.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/protocol.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/telegram/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/telegram/collection.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/telegram/item.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/telegram/methods.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/telegram/tlb.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/vanity/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/vanity/models.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/vanity/tlb.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/vanity/vanity.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/versions.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/configs.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/methods.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/params.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/protocol.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/tlb.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/versions/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/versions/hw.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/versions/pp.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/versions/v1.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/versions/v2.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/versions/v3.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/versions/v4.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/contracts/wallet/versions/v5.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/exceptions.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/py.typed +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/tonconnect/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/tools/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/tools/status_monitor/__init__.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/tools/status_monitor/console.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/tools/status_monitor/models.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/tools/status_monitor/monitor.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils/types.py +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils.egg-info/dependency_links.txt +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils.egg-info/entry_points.txt +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils.egg-info/requires.txt +0 -0
- {tonutils-2.0.1b5 → tonutils-2.0.1b6}/tonutils.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.0.1b6"
|
|
@@ -5,12 +5,12 @@ from .adnl import (
|
|
|
5
5
|
)
|
|
6
6
|
from .http import (
|
|
7
7
|
HttpBalancer,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
ChainstackClient,
|
|
9
|
+
QuicknodeClient,
|
|
10
|
+
TatumClient,
|
|
11
|
+
TonapiClient,
|
|
12
12
|
TonapiHttpProvider,
|
|
13
|
-
|
|
13
|
+
ToncenterClient,
|
|
14
14
|
ToncenterHttpProvider,
|
|
15
15
|
)
|
|
16
16
|
|
|
@@ -19,11 +19,11 @@ __all__ = [
|
|
|
19
19
|
"LiteClient",
|
|
20
20
|
"AdnlProvider",
|
|
21
21
|
"HttpBalancer",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
22
|
+
"ChainstackClient",
|
|
23
|
+
"QuicknodeClient",
|
|
24
|
+
"TatumClient",
|
|
25
|
+
"TonapiClient",
|
|
26
26
|
"TonapiHttpProvider",
|
|
27
|
-
"
|
|
27
|
+
"ToncenterClient",
|
|
28
28
|
"ToncenterHttpProvider",
|
|
29
29
|
]
|
|
@@ -64,8 +64,8 @@ class LiteBalancer(BaseClient):
|
|
|
64
64
|
|
|
65
65
|
def __init__(
|
|
66
66
|
self,
|
|
67
|
-
*,
|
|
68
67
|
network: NetworkGlobalID = NetworkGlobalID.MAINNET,
|
|
68
|
+
*,
|
|
69
69
|
clients: t.List[LiteClient],
|
|
70
70
|
connect_timeout: float = 2.0,
|
|
71
71
|
request_timeout: float = 12.0,
|
|
@@ -206,8 +206,8 @@ class LiteBalancer(BaseClient):
|
|
|
206
206
|
@classmethod
|
|
207
207
|
def from_config(
|
|
208
208
|
cls,
|
|
209
|
-
*,
|
|
210
209
|
network: NetworkGlobalID = NetworkGlobalID.MAINNET,
|
|
210
|
+
*,
|
|
211
211
|
config: t.Union[GlobalConfig, t.Dict[str, t.Any]],
|
|
212
212
|
connect_timeout: float = 2.0,
|
|
213
213
|
request_timeout: float = 12.0,
|
|
@@ -285,8 +285,8 @@ class LiteBalancer(BaseClient):
|
|
|
285
285
|
@classmethod
|
|
286
286
|
def from_network_config(
|
|
287
287
|
cls,
|
|
288
|
-
*,
|
|
289
288
|
network: NetworkGlobalID = NetworkGlobalID.MAINNET,
|
|
289
|
+
*,
|
|
290
290
|
connect_timeout: float = 2.0,
|
|
291
291
|
request_timeout: float = 12.0,
|
|
292
292
|
client_connect_timeout: float = 1.5,
|
|
@@ -513,13 +513,14 @@ class LiteBalancer(BaseClient):
|
|
|
513
513
|
|
|
514
514
|
return await self._with_failover(_call)
|
|
515
515
|
|
|
516
|
-
async def
|
|
516
|
+
async def _get_transactions(
|
|
517
517
|
self,
|
|
518
518
|
address: str,
|
|
519
519
|
limit: int = 100,
|
|
520
520
|
from_lt: t.Optional[int] = None,
|
|
521
|
-
to_lt: int =
|
|
521
|
+
to_lt: t.Optional[int] = None,
|
|
522
522
|
) -> t.List[Transaction]:
|
|
523
|
+
to_lt = 0 if to_lt is None else to_lt
|
|
523
524
|
state = await self._get_contract_info(address)
|
|
524
525
|
account = Address(address).to_tl_account_id()
|
|
525
526
|
|
|
@@ -530,41 +531,37 @@ class LiteBalancer(BaseClient):
|
|
|
530
531
|
curr_hash = state.last_transaction_hash
|
|
531
532
|
transactions: t.List[Transaction] = []
|
|
532
533
|
|
|
533
|
-
while
|
|
534
|
-
|
|
534
|
+
while curr_lt != 0:
|
|
535
|
+
fetch_lt = curr_lt
|
|
536
|
+
fetch_hash = curr_hash
|
|
535
537
|
|
|
536
538
|
async def _call(provider: AdnlProvider) -> t.List[Transaction]:
|
|
537
539
|
return await provider.get_transactions(
|
|
538
540
|
account=account,
|
|
539
|
-
count=
|
|
540
|
-
from_lt=
|
|
541
|
-
from_hash=
|
|
541
|
+
count=16,
|
|
542
|
+
from_lt=fetch_lt,
|
|
543
|
+
from_hash=fetch_hash,
|
|
542
544
|
)
|
|
543
545
|
|
|
544
546
|
txs = await self._with_failover(_call)
|
|
545
547
|
if not txs:
|
|
546
548
|
break
|
|
547
549
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
trimmed.append(tx)
|
|
554
|
-
transactions.extend(trimmed)
|
|
555
|
-
break
|
|
550
|
+
for tx in txs:
|
|
551
|
+
if from_lt is not None and tx.lt > from_lt:
|
|
552
|
+
continue
|
|
553
|
+
if to_lt > 0 and tx.lt <= to_lt:
|
|
554
|
+
return transactions[:limit]
|
|
556
555
|
|
|
557
|
-
|
|
556
|
+
transactions.append(tx)
|
|
557
|
+
if len(transactions) >= limit:
|
|
558
|
+
return transactions
|
|
558
559
|
|
|
559
560
|
last_tx = txs[-1]
|
|
560
561
|
curr_lt = last_tx.prev_trans_lt
|
|
561
562
|
curr_hash = last_tx.prev_trans_hash.hex()
|
|
562
563
|
|
|
563
|
-
return
|
|
564
|
-
[tx for tx in transactions if tx.lt < from_lt]
|
|
565
|
-
if from_lt is not None
|
|
566
|
-
else transactions
|
|
567
|
-
)
|
|
564
|
+
return transactions[:limit]
|
|
568
565
|
|
|
569
566
|
async def _run_get_method(
|
|
570
567
|
self,
|
|
@@ -34,8 +34,8 @@ class LiteClient(BaseClient):
|
|
|
34
34
|
|
|
35
35
|
def __init__(
|
|
36
36
|
self,
|
|
37
|
-
*,
|
|
38
37
|
network: NetworkGlobalID = NetworkGlobalID.MAINNET,
|
|
38
|
+
*,
|
|
39
39
|
ip: t.Union[str, int],
|
|
40
40
|
port: int,
|
|
41
41
|
public_key: BinaryLike,
|
|
@@ -119,8 +119,8 @@ class LiteClient(BaseClient):
|
|
|
119
119
|
@classmethod
|
|
120
120
|
def from_config(
|
|
121
121
|
cls,
|
|
122
|
-
*,
|
|
123
122
|
network: NetworkGlobalID = NetworkGlobalID.MAINNET,
|
|
123
|
+
*,
|
|
124
124
|
config: t.Union[GlobalConfig, t.Dict[str, t.Any]],
|
|
125
125
|
index: int,
|
|
126
126
|
connect_timeout: float = 2.0,
|
|
@@ -170,8 +170,8 @@ class LiteClient(BaseClient):
|
|
|
170
170
|
@classmethod
|
|
171
171
|
def from_network_config(
|
|
172
172
|
cls,
|
|
173
|
-
*,
|
|
174
173
|
network: NetworkGlobalID = NetworkGlobalID.MAINNET,
|
|
174
|
+
*,
|
|
175
175
|
index: int,
|
|
176
176
|
connect_timeout: float = 2.0,
|
|
177
177
|
request_timeout: float = 10.0,
|
|
@@ -225,13 +225,14 @@ class LiteClient(BaseClient):
|
|
|
225
225
|
async def _get_contract_info(self, address: str) -> ContractStateInfo:
|
|
226
226
|
return await self.provider.get_account_state(Address(address))
|
|
227
227
|
|
|
228
|
-
async def
|
|
228
|
+
async def _get_transactions(
|
|
229
229
|
self,
|
|
230
230
|
address: str,
|
|
231
231
|
limit: int = 100,
|
|
232
232
|
from_lt: t.Optional[int] = None,
|
|
233
|
-
to_lt: int =
|
|
233
|
+
to_lt: t.Optional[int] = None,
|
|
234
234
|
) -> t.List[Transaction]:
|
|
235
|
+
to_lt = 0 if to_lt is None else to_lt
|
|
235
236
|
state = await self._get_contract_info(address)
|
|
236
237
|
account = Address(address).to_tl_account_id()
|
|
237
238
|
|
|
@@ -242,38 +243,34 @@ class LiteClient(BaseClient):
|
|
|
242
243
|
curr_hash = state.last_transaction_hash
|
|
243
244
|
transactions: t.List[Transaction] = []
|
|
244
245
|
|
|
245
|
-
while
|
|
246
|
-
|
|
246
|
+
while curr_lt != 0:
|
|
247
|
+
fetch_lt = curr_lt
|
|
248
|
+
fetch_hash = curr_hash
|
|
247
249
|
|
|
248
250
|
txs = await self.provider.get_transactions(
|
|
249
251
|
account=account,
|
|
250
|
-
count=
|
|
251
|
-
from_lt=
|
|
252
|
-
from_hash=
|
|
252
|
+
count=16,
|
|
253
|
+
from_lt=fetch_lt,
|
|
254
|
+
from_hash=fetch_hash,
|
|
253
255
|
)
|
|
254
256
|
if not txs:
|
|
255
257
|
break
|
|
256
258
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
trimmed.append(tx)
|
|
263
|
-
transactions.extend(trimmed)
|
|
264
|
-
break
|
|
259
|
+
for tx in txs:
|
|
260
|
+
if from_lt is not None and tx.lt > from_lt:
|
|
261
|
+
continue
|
|
262
|
+
if to_lt > 0 and tx.lt <= to_lt:
|
|
263
|
+
return transactions[:limit]
|
|
265
264
|
|
|
266
|
-
|
|
265
|
+
transactions.append(tx)
|
|
266
|
+
if len(transactions) >= limit:
|
|
267
|
+
return transactions
|
|
267
268
|
|
|
268
269
|
last_tx = txs[-1]
|
|
269
270
|
curr_lt = last_tx.prev_trans_lt
|
|
270
271
|
curr_hash = last_tx.prev_trans_hash.hex()
|
|
271
272
|
|
|
272
|
-
return
|
|
273
|
-
[tx for tx in transactions if tx.lt < from_lt]
|
|
274
|
-
if from_lt is not None
|
|
275
|
-
else transactions
|
|
276
|
-
)
|
|
273
|
+
return transactions[:limit]
|
|
277
274
|
|
|
278
275
|
async def _run_get_method(
|
|
279
276
|
self,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import urllib.request
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from urllib.error import HTTPError, URLError
|
|
5
|
+
|
|
6
|
+
from pydantic import ValidationError
|
|
7
|
+
|
|
8
|
+
from tonutils.clients.adnl.provider.models import GlobalConfig
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def load_global_config(source: str) -> GlobalConfig:
|
|
12
|
+
try:
|
|
13
|
+
if source.startswith(("http://", "https://")):
|
|
14
|
+
with urllib.request.urlopen(source) as r:
|
|
15
|
+
data = json.loads(r.read().decode("utf-8"))
|
|
16
|
+
else:
|
|
17
|
+
data = json.loads(Path(source).read_text(encoding="utf-8"))
|
|
18
|
+
return GlobalConfig.model_validate(data)
|
|
19
|
+
except HTTPError as e:
|
|
20
|
+
raise RuntimeError(f"Config fetch failed: {e} ({source})") from e
|
|
21
|
+
except URLError as e:
|
|
22
|
+
raise RuntimeError(f"Config fetch failed: {e.reason} ({source})") from e
|
|
23
|
+
except json.JSONDecodeError as e:
|
|
24
|
+
raise RuntimeError(f"Config JSON is invalid: {e.msg} ({source})") from e
|
|
25
|
+
except ValidationError as e:
|
|
26
|
+
raise RuntimeError(f"Config validation failed: {e} ({source})") from e
|
|
27
|
+
except OSError as e:
|
|
28
|
+
raise RuntimeError(f"Config read failed: {e} ({source})") from e
|
|
29
|
+
except Exception as e:
|
|
30
|
+
raise RuntimeError(f"Config load failed: {e} ({source})") from e
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_mainnet_global_config() -> GlobalConfig:
|
|
34
|
+
"""
|
|
35
|
+
Fetch mainnet global configuration.
|
|
36
|
+
|
|
37
|
+
:return: Parsed GlobalConfig instance
|
|
38
|
+
"""
|
|
39
|
+
return load_global_config("https://ton.org/global-config.json")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def get_testnet_global_config() -> GlobalConfig:
|
|
43
|
+
"""
|
|
44
|
+
Fetch testnet global configuration.
|
|
45
|
+
|
|
46
|
+
:return: Parsed GlobalConfig instance
|
|
47
|
+
"""
|
|
48
|
+
return load_global_config("https://ton.org/testnet-global-config.json")
|
|
@@ -98,20 +98,23 @@ class BaseClient(abc.ABC):
|
|
|
98
98
|
raise NotImplementedError
|
|
99
99
|
|
|
100
100
|
@abc.abstractmethod
|
|
101
|
-
async def
|
|
101
|
+
async def _get_transactions(
|
|
102
102
|
self,
|
|
103
103
|
address: str,
|
|
104
104
|
limit: int = 100,
|
|
105
105
|
from_lt: t.Optional[int] = None,
|
|
106
|
-
to_lt: int =
|
|
106
|
+
to_lt: t.Optional[int] = None,
|
|
107
107
|
) -> t.List[Transaction]:
|
|
108
108
|
"""
|
|
109
|
-
Fetch
|
|
109
|
+
Fetch transaction history for a contract.
|
|
110
|
+
Returns transactions in the range (to_lt, from_lt), ordered from newest to oldest.
|
|
110
111
|
|
|
111
|
-
:param address: Contract address
|
|
112
|
+
:param address: Contract address as string
|
|
112
113
|
:param limit: Maximum number of transactions to return
|
|
113
|
-
:param from_lt:
|
|
114
|
-
|
|
114
|
+
:param from_lt: Upper bound logical time (inclusive).
|
|
115
|
+
If None, starts from the most recent transaction.
|
|
116
|
+
:param to_lt: Lower bound logical time (exclusive).
|
|
117
|
+
If None or 0, no lower bound is applied.
|
|
115
118
|
:return: List of Transaction objects ordered from newest to oldest
|
|
116
119
|
"""
|
|
117
120
|
raise NotImplementedError
|
|
@@ -180,25 +183,28 @@ class BaseClient(abc.ABC):
|
|
|
180
183
|
address = Address(address).to_str(is_user_friendly=False)
|
|
181
184
|
return await self._get_contract_info(address=address)
|
|
182
185
|
|
|
183
|
-
async def
|
|
186
|
+
async def get_transactions(
|
|
184
187
|
self,
|
|
185
188
|
address: AddressLike,
|
|
186
189
|
limit: int = 100,
|
|
187
190
|
from_lt: t.Optional[int] = None,
|
|
188
|
-
to_lt: int =
|
|
191
|
+
to_lt: t.Optional[int] = None,
|
|
189
192
|
) -> t.List[Transaction]:
|
|
190
193
|
"""
|
|
191
194
|
Fetch transaction history for a contract.
|
|
195
|
+
Returns transactions in the range (to_lt, from_lt), ordered from newest to oldest.
|
|
192
196
|
|
|
193
197
|
:param address: Contract address as Address object or string
|
|
194
198
|
:param limit: Maximum number of transactions to return
|
|
195
|
-
:param from_lt:
|
|
196
|
-
|
|
199
|
+
:param from_lt: Upper bound logical time (inclusive).
|
|
200
|
+
If None, starts from the most recent transaction.
|
|
201
|
+
:param to_lt: Lower bound logical time (exclusive).
|
|
202
|
+
If None or 0, no lower bound is applied.
|
|
197
203
|
:return: List of Transaction objects ordered from newest to oldest
|
|
198
204
|
"""
|
|
199
205
|
if isinstance(address, Address):
|
|
200
206
|
address = Address(address).to_str(is_user_friendly=False)
|
|
201
|
-
return await self.
|
|
207
|
+
return await self._get_transactions(
|
|
202
208
|
address=address,
|
|
203
209
|
limit=limit,
|
|
204
210
|
from_lt=from_lt,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from .balancer import HttpBalancer
|
|
2
|
+
from .clients import (
|
|
3
|
+
ChainstackClient,
|
|
4
|
+
QuicknodeClient,
|
|
5
|
+
TatumClient,
|
|
6
|
+
TonapiClient,
|
|
7
|
+
ToncenterClient,
|
|
8
|
+
)
|
|
9
|
+
from .provider import (
|
|
10
|
+
TonapiHttpProvider,
|
|
11
|
+
ToncenterHttpProvider,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"HttpBalancer",
|
|
16
|
+
"ChainstackClient",
|
|
17
|
+
"QuicknodeClient",
|
|
18
|
+
"TatumClient",
|
|
19
|
+
"TonapiClient",
|
|
20
|
+
"TonapiHttpProvider",
|
|
21
|
+
"ToncenterClient",
|
|
22
|
+
"ToncenterHttpProvider",
|
|
23
|
+
]
|
|
@@ -10,7 +10,7 @@ from itertools import cycle
|
|
|
10
10
|
from pytoniq_core import Transaction
|
|
11
11
|
|
|
12
12
|
from tonutils.clients.base import BaseClient
|
|
13
|
-
from tonutils.clients.http.clients.quicknode import
|
|
13
|
+
from tonutils.clients.http.clients.quicknode import QuicknodeClient
|
|
14
14
|
from tonutils.exceptions import (
|
|
15
15
|
BalancerError,
|
|
16
16
|
ClientError,
|
|
@@ -50,8 +50,8 @@ class HttpBalancer(BaseClient):
|
|
|
50
50
|
|
|
51
51
|
def __init__(
|
|
52
52
|
self,
|
|
53
|
-
*,
|
|
54
53
|
network: NetworkGlobalID = NetworkGlobalID.MAINNET,
|
|
54
|
+
*,
|
|
55
55
|
clients: t.List[BaseClient],
|
|
56
56
|
request_timeout: float = 12.0,
|
|
57
57
|
) -> None:
|
|
@@ -60,15 +60,15 @@ class HttpBalancer(BaseClient):
|
|
|
60
60
|
|
|
61
61
|
Each supported HTTP client requires its own credentials or endpoint
|
|
62
62
|
configuration. You can obtain them from the corresponding provider:
|
|
63
|
-
-
|
|
63
|
+
- ToncenterClient:
|
|
64
64
|
API key available via Telegram bot: https://t.me/toncenter
|
|
65
|
-
-
|
|
65
|
+
- TonapiClient:
|
|
66
66
|
API key available on the Tonconsole website: https://tonconsole.com/
|
|
67
|
-
-
|
|
67
|
+
- ChainstackClient:
|
|
68
68
|
Personal endpoint available on: https://chainstack.com/
|
|
69
|
-
-
|
|
69
|
+
- QuicknodeClient:
|
|
70
70
|
Personal endpoint available on: https://www.quicknode.com/
|
|
71
|
-
-
|
|
71
|
+
- TatumClient:
|
|
72
72
|
API key available on: https://tatum.io/
|
|
73
73
|
|
|
74
74
|
:param network: Target TON network (mainnet or testnet)
|
|
@@ -102,7 +102,7 @@ class HttpBalancer(BaseClient):
|
|
|
102
102
|
)
|
|
103
103
|
|
|
104
104
|
if (
|
|
105
|
-
isinstance(client,
|
|
105
|
+
isinstance(client, QuicknodeClient)
|
|
106
106
|
and self.network == NetworkGlobalID.TESTNET
|
|
107
107
|
):
|
|
108
108
|
raise ClientError(
|
|
@@ -356,15 +356,15 @@ class HttpBalancer(BaseClient):
|
|
|
356
356
|
|
|
357
357
|
return await self._with_failover(_call)
|
|
358
358
|
|
|
359
|
-
async def
|
|
359
|
+
async def _get_transactions(
|
|
360
360
|
self,
|
|
361
361
|
address: str,
|
|
362
362
|
limit: int = 100,
|
|
363
363
|
from_lt: t.Optional[int] = None,
|
|
364
|
-
to_lt: int =
|
|
364
|
+
to_lt: t.Optional[int] = None,
|
|
365
365
|
) -> t.List[Transaction]:
|
|
366
366
|
async def _call(client: BaseClient) -> t.List[Transaction]:
|
|
367
|
-
return await client.
|
|
367
|
+
return await client._get_transactions(
|
|
368
368
|
address=address,
|
|
369
369
|
limit=limit,
|
|
370
370
|
from_lt=from_lt,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .chainstack import ChainstackClient
|
|
2
|
+
from .quicknode import QuicknodeClient
|
|
3
|
+
from .tatum import TatumClient
|
|
4
|
+
from .tonapi import TonapiClient
|
|
5
|
+
from .toncenter import ToncenterClient
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"ChainstackClient",
|
|
9
|
+
"QuicknodeClient",
|
|
10
|
+
"TatumClient",
|
|
11
|
+
"TonapiClient",
|
|
12
|
+
"ToncenterClient",
|
|
13
|
+
]
|
|
@@ -2,16 +2,16 @@ import typing as t
|
|
|
2
2
|
|
|
3
3
|
from aiohttp import ClientSession
|
|
4
4
|
|
|
5
|
-
from tonutils.clients.http.clients.toncenter import
|
|
5
|
+
from tonutils.clients.http.clients.toncenter import ToncenterClient
|
|
6
6
|
from tonutils.types import NetworkGlobalID, RetryPolicy
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class ChainstackClient(ToncenterClient):
|
|
10
10
|
|
|
11
11
|
def __init__(
|
|
12
12
|
self,
|
|
13
|
-
*,
|
|
14
13
|
network: NetworkGlobalID,
|
|
14
|
+
*,
|
|
15
15
|
http_provider_url: str,
|
|
16
16
|
timeout: float = 10.0,
|
|
17
17
|
session: t.Optional[ClientSession] = None,
|
|
@@ -2,11 +2,11 @@ import typing as t
|
|
|
2
2
|
|
|
3
3
|
from aiohttp import ClientSession
|
|
4
4
|
|
|
5
|
-
from tonutils.clients.http.clients.toncenter import
|
|
5
|
+
from tonutils.clients.http.clients.toncenter import ToncenterClient
|
|
6
6
|
from tonutils.types import NetworkGlobalID, RetryPolicy
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class QuicknodeClient(ToncenterClient):
|
|
10
10
|
|
|
11
11
|
def __init__(
|
|
12
12
|
self,
|
|
@@ -33,7 +33,6 @@ class QuicknodeHttpClient(ToncenterHttpClient):
|
|
|
33
33
|
:param rps_period: Rate limit period in seconds.
|
|
34
34
|
:param retry_policy: Optional retry policy that defines per-error-code retry rules
|
|
35
35
|
"""
|
|
36
|
-
|
|
37
36
|
super().__init__(
|
|
38
37
|
network=NetworkGlobalID.MAINNET,
|
|
39
38
|
base_url=http_provider_url,
|
|
@@ -2,16 +2,16 @@ import typing as t
|
|
|
2
2
|
|
|
3
3
|
from aiohttp import ClientSession
|
|
4
4
|
|
|
5
|
-
from tonutils.clients.http.clients.toncenter import
|
|
5
|
+
from tonutils.clients.http.clients.toncenter import ToncenterClient
|
|
6
6
|
from tonutils.types import NetworkGlobalID, RetryPolicy
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class TatumClient(ToncenterClient):
|
|
10
10
|
|
|
11
11
|
def __init__(
|
|
12
12
|
self,
|
|
13
|
-
*,
|
|
14
13
|
network: NetworkGlobalID,
|
|
14
|
+
*,
|
|
15
15
|
api_key: str,
|
|
16
16
|
base_url: t.Optional[str] = None,
|
|
17
17
|
timeout: float = 10.0,
|
|
@@ -6,8 +6,8 @@ from aiohttp import ClientSession
|
|
|
6
6
|
from pytoniq_core import Cell, Slice, Transaction
|
|
7
7
|
|
|
8
8
|
from tonutils.clients.base import BaseClient
|
|
9
|
-
from tonutils.clients.http.
|
|
10
|
-
from tonutils.clients.http.
|
|
9
|
+
from tonutils.clients.http.provider.models import BlockchainMessagePayload
|
|
10
|
+
from tonutils.clients.http.provider.tonapi import TonapiHttpProvider
|
|
11
11
|
from tonutils.clients.http.utils import encode_tonapi_stack, decode_tonapi_stack
|
|
12
12
|
from tonutils.exceptions import ClientError, RunGetMethodError
|
|
13
13
|
from tonutils.types import (
|
|
@@ -23,15 +23,15 @@ from tonutils.utils import (
|
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
class
|
|
26
|
+
class TonapiClient(BaseClient):
|
|
27
27
|
"""TON blockchain client using Tonapi HTTP API as transport."""
|
|
28
28
|
|
|
29
29
|
TYPE = ClientType.HTTP
|
|
30
30
|
|
|
31
31
|
def __init__(
|
|
32
32
|
self,
|
|
33
|
-
*,
|
|
34
33
|
network: NetworkGlobalID = NetworkGlobalID.MAINNET,
|
|
34
|
+
*,
|
|
35
35
|
api_key: str,
|
|
36
36
|
base_url: t.Optional[str] = None,
|
|
37
37
|
timeout: float = 10.0,
|
|
@@ -80,7 +80,7 @@ class TonapiHttpClient(BaseClient):
|
|
|
80
80
|
session = self._provider.session
|
|
81
81
|
return session is not None and not session.closed
|
|
82
82
|
|
|
83
|
-
async def __aenter__(self) ->
|
|
83
|
+
async def __aenter__(self) -> TonapiClient:
|
|
84
84
|
await self._provider.connect()
|
|
85
85
|
return self
|
|
86
86
|
|
|
@@ -122,21 +122,20 @@ class TonapiHttpClient(BaseClient):
|
|
|
122
122
|
|
|
123
123
|
return contract_info
|
|
124
124
|
|
|
125
|
-
async def
|
|
125
|
+
async def _get_transactions(
|
|
126
126
|
self,
|
|
127
127
|
address: str,
|
|
128
128
|
limit: int = 100,
|
|
129
129
|
from_lt: t.Optional[int] = None,
|
|
130
|
-
to_lt: int =
|
|
130
|
+
to_lt: t.Optional[int] = None,
|
|
131
131
|
) -> t.List[Transaction]:
|
|
132
|
-
if from_lt is not None
|
|
133
|
-
from_lt += 1
|
|
132
|
+
before_lt = from_lt + 1 if from_lt is not None else None
|
|
134
133
|
|
|
135
134
|
result = await self.provider.blockchain_account_transactions(
|
|
136
135
|
address=address,
|
|
137
136
|
limit=limit,
|
|
138
137
|
after_lt=to_lt,
|
|
139
|
-
before_lt=
|
|
138
|
+
before_lt=before_lt,
|
|
140
139
|
)
|
|
141
140
|
|
|
142
141
|
transactions = []
|