tonutils 2.0.1b2__py3-none-any.whl → 2.0.1b4__py3-none-any.whl

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.
Files changed (91) hide show
  1. tonutils/__init__.py +0 -2
  2. tonutils/__meta__.py +1 -1
  3. tonutils/cli.py +111 -0
  4. tonutils/clients/__init__.py +7 -11
  5. tonutils/clients/adnl/__init__.py +7 -3
  6. tonutils/clients/adnl/balancer.py +362 -168
  7. tonutils/clients/adnl/client.py +203 -67
  8. tonutils/clients/adnl/provider/config.py +24 -25
  9. tonutils/clients/adnl/provider/models.py +4 -0
  10. tonutils/clients/adnl/provider/provider.py +203 -160
  11. tonutils/clients/adnl/provider/transport.py +44 -33
  12. tonutils/clients/adnl/provider/workers/base.py +0 -2
  13. tonutils/clients/adnl/provider/workers/pinger.py +1 -1
  14. tonutils/clients/adnl/provider/workers/reader.py +3 -2
  15. tonutils/clients/adnl/{provider/builder.py → utils.py} +62 -2
  16. tonutils/clients/http/__init__.py +11 -8
  17. tonutils/clients/http/balancer.py +75 -63
  18. tonutils/clients/http/clients/__init__.py +13 -0
  19. tonutils/clients/http/clients/chainstack.py +48 -0
  20. tonutils/clients/http/clients/quicknode.py +47 -0
  21. tonutils/clients/http/clients/tatum.py +56 -0
  22. tonutils/clients/http/{tonapi/client.py → clients/tonapi.py} +31 -31
  23. tonutils/clients/http/{toncenter/client.py → clients/toncenter.py} +59 -48
  24. tonutils/clients/http/providers/__init__.py +4 -0
  25. tonutils/clients/http/providers/base.py +201 -0
  26. tonutils/clients/http/providers/response.py +85 -0
  27. tonutils/clients/http/providers/tonapi/__init__.py +3 -0
  28. tonutils/clients/http/{tonapi → providers/tonapi}/models.py +1 -0
  29. tonutils/clients/http/providers/tonapi/provider.py +125 -0
  30. tonutils/clients/http/providers/toncenter/__init__.py +3 -0
  31. tonutils/clients/http/{toncenter → providers/toncenter}/models.py +1 -0
  32. tonutils/clients/http/providers/toncenter/provider.py +119 -0
  33. tonutils/clients/http/utils.py +140 -0
  34. tonutils/clients/limiter.py +115 -0
  35. tonutils/contracts/__init__.py +4 -0
  36. tonutils/contracts/base.py +33 -20
  37. tonutils/contracts/dns/methods.py +2 -2
  38. tonutils/contracts/jetton/methods.py +2 -2
  39. tonutils/contracts/nft/methods.py +2 -2
  40. tonutils/contracts/nft/tlb.py +1 -1
  41. tonutils/{protocols/contract.py → contracts/protocol.py} +29 -29
  42. tonutils/contracts/telegram/methods.py +2 -2
  43. tonutils/contracts/vanity/vanity.py +1 -1
  44. tonutils/contracts/wallet/__init__.py +2 -0
  45. tonutils/contracts/wallet/base.py +3 -3
  46. tonutils/contracts/wallet/messages.py +1 -1
  47. tonutils/contracts/wallet/methods.py +2 -2
  48. tonutils/{protocols/wallet.py → contracts/wallet/protocol.py} +35 -35
  49. tonutils/contracts/wallet/versions/v5.py +3 -3
  50. tonutils/exceptions.py +146 -228
  51. tonutils/tonconnect/__init__.py +0 -0
  52. tonutils/tools/__init__.py +6 -0
  53. tonutils/tools/block_scanner/__init__.py +26 -0
  54. tonutils/tools/block_scanner/annotations.py +23 -0
  55. tonutils/tools/block_scanner/dispatcher.py +141 -0
  56. tonutils/tools/block_scanner/events.py +31 -0
  57. tonutils/tools/block_scanner/scanner.py +315 -0
  58. tonutils/tools/block_scanner/traversal.py +96 -0
  59. tonutils/tools/block_scanner/where.py +151 -0
  60. tonutils/tools/status_monitor/__init__.py +3 -0
  61. tonutils/tools/status_monitor/console.py +157 -0
  62. tonutils/tools/status_monitor/models.py +27 -0
  63. tonutils/tools/status_monitor/monitor.py +295 -0
  64. tonutils/types.py +125 -2
  65. tonutils/utils.py +3 -3
  66. {tonutils-2.0.1b2.dist-info → tonutils-2.0.1b4.dist-info}/METADATA +2 -5
  67. tonutils-2.0.1b4.dist-info/RECORD +108 -0
  68. tonutils-2.0.1b4.dist-info/entry_points.txt +2 -0
  69. tonutils/clients/adnl/provider/limiter.py +0 -56
  70. tonutils/clients/adnl/stack.py +0 -64
  71. tonutils/clients/http/chainstack/__init__.py +0 -4
  72. tonutils/clients/http/chainstack/client.py +0 -63
  73. tonutils/clients/http/chainstack/provider.py +0 -44
  74. tonutils/clients/http/quicknode/__init__.py +0 -4
  75. tonutils/clients/http/quicknode/client.py +0 -60
  76. tonutils/clients/http/quicknode/provider.py +0 -42
  77. tonutils/clients/http/tatum/__init__.py +0 -4
  78. tonutils/clients/http/tatum/client.py +0 -66
  79. tonutils/clients/http/tatum/provider.py +0 -53
  80. tonutils/clients/http/tonapi/__init__.py +0 -4
  81. tonutils/clients/http/tonapi/provider.py +0 -150
  82. tonutils/clients/http/tonapi/stack.py +0 -71
  83. tonutils/clients/http/toncenter/__init__.py +0 -4
  84. tonutils/clients/http/toncenter/provider.py +0 -145
  85. tonutils/clients/http/toncenter/stack.py +0 -73
  86. tonutils/protocols/__init__.py +0 -9
  87. tonutils-2.0.1b2.dist-info/RECORD +0 -98
  88. /tonutils/{protocols/client.py → clients/protocol.py} +0 -0
  89. {tonutils-2.0.1b2.dist-info → tonutils-2.0.1b4.dist-info}/WHEEL +0 -0
  90. {tonutils-2.0.1b2.dist-info → tonutils-2.0.1b4.dist-info}/licenses/LICENSE +0 -0
  91. {tonutils-2.0.1b2.dist-info → tonutils-2.0.1b4.dist-info}/top_level.txt +0 -0
@@ -18,12 +18,6 @@ from pytoniq_core import (
18
18
  from pytoniq_core.crypto.ciphers import get_random
19
19
  from pytoniq_core.crypto.crc import crc16
20
20
 
21
- from tonutils.clients.adnl.provider.builder import (
22
- build_contract_state_info,
23
- build_shard_account,
24
- build_config_all,
25
- )
26
- from tonutils.clients.adnl.provider.limiter import PriorityLimiter
27
21
  from tonutils.clients.adnl.provider.models import LiteServer, MasterchainInfo
28
22
  from tonutils.clients.adnl.provider.transport import AdnlTcpTransport
29
23
  from tonutils.clients.adnl.provider.workers import (
@@ -31,35 +25,38 @@ from tonutils.clients.adnl.provider.workers import (
31
25
  ReaderWorker,
32
26
  UpdaterWorker,
33
27
  )
28
+ from tonutils.clients.adnl.utils import (
29
+ build_contract_state_info,
30
+ build_shard_account,
31
+ build_config_all,
32
+ )
33
+ from tonutils.clients.limiter import RateLimiter
34
34
  from tonutils.exceptions import (
35
- AdnlHandshakeError,
36
- AdnlProviderConnectError,
37
- AdnlServerError,
38
- AdnlProviderMissingBlockError,
39
- AdnlProviderResponseError,
40
- AdnlProviderClosedError,
41
35
  ClientError,
42
- ClientNotConnectedError,
43
- RateLimitExceededError,
36
+ NotConnectedError,
37
+ ProviderError,
44
38
  RunGetMethodError,
39
+ ProviderTimeoutError,
40
+ RetryLimitError,
41
+ ProviderResponseError,
42
+ )
43
+ from tonutils.types import (
44
+ ContractStateInfo,
45
+ RetryPolicy,
46
+ WorkchainID,
45
47
  )
46
- from tonutils.types import ContractStateInfo, WorkchainID
47
48
 
48
49
 
49
50
  class AdnlProvider:
50
- """
51
- ADNL-based provider for TON lite-servers.
52
-
53
- Handles encrypted TCP transport, ping and masterchain updates, and exposes
54
- a high-level API for lite-server queries.
55
- """
51
+ """ADNL-based provider for TON lite-servers."""
56
52
 
57
53
  def __init__(
58
54
  self,
59
55
  node: LiteServer,
60
- timeout: int = 10,
61
- rps_retries: t.Optional[int] = None,
62
- limiter: t.Optional[PriorityLimiter] = None,
56
+ connect_timeout: float = 2.0,
57
+ request_timeout: float = 10.0,
58
+ limiter: t.Optional[RateLimiter] = None,
59
+ retry_policy: t.Optional[RetryPolicy] = None,
63
60
  ) -> None:
64
61
  """
65
62
  Initialize ADNL provider for a specific lite-server.
@@ -71,14 +68,15 @@ class AdnlProvider:
71
68
  - dTON telegram bot: https://t.me/dtontech_bot (https://dton.io/)
72
69
 
73
70
  :param node: LiteServer configuration (host, port, public key)
74
- :param timeout: Timeout in seconds for queries
75
- :param rps_retries: Number of retries on rate limiting
71
+ :param connect_timeout: Timeout in seconds for connect/reconnect
72
+ :param request_timeout: Timeout in seconds for queries
76
73
  :param limiter: Optional priority-aware rate limiter
74
+ :param retry_policy: Optional retry policy that defines per-error-code retry rules
77
75
  """
78
76
  self.node = node
79
- self.timeout = timeout
80
- self.rps_retries = rps_retries
81
- self.transport = AdnlTcpTransport(self.node, self.timeout)
77
+ self.connect_timeout = connect_timeout
78
+ self.request_timeout = request_timeout
79
+ self.transport = AdnlTcpTransport(self.node, self.connect_timeout)
82
80
  self.loop: t.Optional[asyncio.AbstractEventLoop] = None
83
81
 
84
82
  self.tl_schemas = TlGenerator.with_default_schemas().generate()
@@ -92,15 +90,16 @@ class AdnlProvider:
92
90
 
93
91
  self.pending: t.Dict[str, asyncio.Future] = {}
94
92
 
93
+ self._limiter: t.Optional[RateLimiter] = limiter
94
+ self._retry_policy: t.Optional[RetryPolicy] = retry_policy
95
95
  self._connect_lock: asyncio.Lock = asyncio.Lock()
96
- self._limiter: t.Optional[PriorityLimiter] = limiter
97
96
 
98
97
  @property
99
98
  def is_connected(self) -> bool:
100
99
  """
101
- Check whether the underlying transport is connected.
100
+ Whether the underlying transport is currently connected.
102
101
 
103
- :return: True if ADNL transport is connected, False otherwise
102
+ :return: True if connected, False otherwise
104
103
  """
105
104
  return self.transport.is_connected
106
105
 
@@ -134,9 +133,9 @@ class AdnlProvider:
134
133
  @property
135
134
  def last_ping_ms(self) -> t.Optional[int]:
136
135
  """
137
- Round-trip time of the last ping in milliseconds.
136
+ Round-trip time of the last successful ping.
138
137
 
139
- :return: Ping RTT in milliseconds or None if unknown
138
+ :return: Ping RTT in milliseconds, or None if unknown
140
139
  """
141
140
  if self.last_ping_rtt is None:
142
141
  return None
@@ -170,20 +169,7 @@ class AdnlProvider:
170
169
  return
171
170
 
172
171
  self.loop = asyncio.get_running_loop()
173
- try:
174
- await self.transport.connect()
175
- except AdnlHandshakeError as exc:
176
- raise AdnlProviderConnectError(
177
- host=self.node.host,
178
- port=self.node.port,
179
- message=str(exc),
180
- ) from exc
181
- except OSError as exc:
182
- raise AdnlProviderConnectError(
183
- host=self.node.host,
184
- port=self.node.port,
185
- message=str(exc),
186
- ) from exc
172
+ await self.transport.connect()
187
173
 
188
174
  tasks = [self.reader.start(), self.pinger.start(), self.updater.start()]
189
175
  await asyncio.gather(*tasks, return_exceptions=True)
@@ -221,124 +207,93 @@ class AdnlProvider:
221
207
  async with self._connect_lock:
222
208
  await self._do_close()
223
209
 
224
- async def send_adnl_query(
225
- self,
226
- query: bytes,
227
- priority: bool = False,
228
- ) -> dict:
210
+ async def _send_once_adnl_query(self, query: bytes, *, priority: bool) -> dict:
229
211
  """
230
- Send a raw ADNL query with retry support for rate-limit and missing-block conditions.
231
-
232
- Retries temporary overload errors (228, 5556) and missing-block errors (651)
233
- before returning a response or raising an exception.
212
+ Send a single ADNL query.
234
213
 
235
214
  :param query: Encoded ADNL TL-query bytes
236
215
  :param priority: Whether to use priority slot in the limiter
237
216
  :return: Lite-server response payload as a decoded dictionary
238
217
  """
239
- return await self._send_with_missing_block_retries(query, priority)
218
+ if not self.is_connected or self.loop is None:
219
+ raise NotConnectedError()
240
220
 
241
- async def _send_with_missing_block_retries(
242
- self,
243
- query: bytes,
244
- priority: bool = False,
245
- ) -> dict:
246
- """
247
- Internal wrapper adding retry handling for missing-block errors (code 651).
221
+ if self._limiter is not None:
222
+ await self._limiter.acquire(priority=priority)
248
223
 
249
- Performs a fixed number of attempts with exponential backoff on 651 and
250
- delegates transport-level and rate-limit handling to `_send_with_rps_retries`.
224
+ query_id = get_random(32)
225
+ packet = self.tl_schemas.serialize(
226
+ self.adnl_query_tl_schema,
227
+ {"query_id": query_id, "query": query},
228
+ )
251
229
 
252
- :param query: Encoded ADNL TL-query bytes
253
- :param priority: Whether to use priority slot in the limiter
254
- :return: Lite-server response payload as a dictionary
255
- """
256
- max_651_retries = 5
257
- error_message = "unknown lite-server error"
230
+ query_id_key = query_id[::-1].hex()
231
+ fut: asyncio.Future[t.Any] = self.loop.create_future()
232
+ self.pending[query_id_key] = fut
233
+
234
+ try:
235
+ await self.transport.send_adnl_packet(packet)
258
236
 
259
- for attempt in range(max_651_retries):
260
237
  try:
261
- return await self._send_with_rps_retries(query, priority=priority)
262
- except AdnlServerError as e:
263
- if e.code != 651:
264
- raise
265
- error_message = e.message
266
- if attempt < max_651_retries - 1:
267
- await asyncio.sleep(0.3 * (2**attempt))
268
- continue
269
- break
270
-
271
- raise AdnlProviderMissingBlockError(
272
- attempts=max_651_retries,
273
- host=self.node.host,
274
- port=self.node.port,
275
- message=error_message,
276
- )
238
+ resp = await asyncio.wait_for(fut, timeout=self.request_timeout)
239
+ except asyncio.TimeoutError as exc:
240
+ raise ProviderTimeoutError(
241
+ timeout=self.request_timeout,
242
+ endpoint=self.node.endpoint,
243
+ operation="request",
244
+ ) from exc
245
+
246
+ if not isinstance(resp, dict):
247
+ raise ProviderError(f"invalid response type: {type(resp).__name__}")
248
+ return resp
249
+
250
+ finally:
251
+ if query_id_key in self.pending:
252
+ del self.pending[query_id_key]
277
253
 
278
- async def _send_with_rps_retries(
254
+ async def send_adnl_query(
279
255
  self,
280
256
  query: bytes,
281
257
  priority: bool = False,
282
258
  ) -> dict:
283
259
  """
284
- Internal ADNL request executor with retry handling for rate-limit errors.
260
+ Send a raw ADNL query with retry handling based on retry policy.
285
261
 
286
- Performs a bounded number of attempts on lite-server overload conditions
287
- (error codes 228 and 5556) using exponential backoff before failing.
262
+ On server error, retries the request according to the rule associated
263
+ with the received error code. If no rule matches, or retry attempts are
264
+ exhausted, the error is raised.
288
265
 
289
266
  :param query: Encoded ADNL TL-query bytes
290
267
  :param priority: Whether to use priority slot in the limiter
291
- :return: Lite-server response payload as a dictionary
268
+ :return: Lite-server response payload as a decoded dictionary
292
269
  """
293
- if not self.is_connected or self.loop is None:
294
- raise ClientNotConnectedError(self)
295
-
296
- attempts = max(self.rps_retries or 0, 1)
297
- for attempt in range(attempts):
298
- if self._limiter is not None:
299
- await self._limiter.acquire(priority=priority)
300
-
301
- query_id = get_random(32)
302
- packet = self.tl_schemas.serialize(
303
- self.adnl_query_tl_schema,
304
- {
305
- "query_id": query_id,
306
- "query": query,
307
- },
308
- )
309
- query_id_key = query_id[::-1].hex()
310
- fut: asyncio.Future = self.loop.create_future()
311
- self.pending[query_id_key] = fut
270
+ attempts: t.Dict[int, int] = {}
312
271
 
272
+ while True:
313
273
  try:
314
- await self.transport.send_adnl_packet(packet)
315
- try:
316
- resp = await asyncio.wait_for(fut, timeout=self.timeout)
317
- except asyncio.TimeoutError:
274
+ return await self._send_once_adnl_query(query, priority=priority)
275
+
276
+ except ProviderResponseError as e:
277
+ policy = self._retry_policy
278
+ if policy is None:
318
279
  raise
319
- except asyncio.CancelledError as exc:
320
- raise AdnlProviderClosedError(
321
- host=self.node.host,
322
- port=self.node.port,
323
- ) from exc
324
- except AdnlServerError as e:
325
- if e.code in (228, 5556):
326
- if attempt < attempts - 1:
327
- await asyncio.sleep(0.3 * (2**attempt))
328
- continue
329
- break
280
+
281
+ rule = policy.rule_for(e.code, e.message)
282
+ if rule is None:
330
283
  raise
331
- if not isinstance(resp, dict):
332
- raise AdnlProviderResponseError(
333
- host=self.node.host,
334
- port=self.node.port,
335
- )
336
- return resp
337
- finally:
338
- if query_id_key in self.pending:
339
- del self.pending[query_id_key]
340
-
341
- raise RateLimitExceededError(attempts)
284
+
285
+ key = id(rule)
286
+ n = attempts.get(key, 0) + 1
287
+ attempts[key] = n
288
+
289
+ if n >= rule.attempts:
290
+ raise RetryLimitError(
291
+ attempts=n,
292
+ max_attempts=rule.attempts,
293
+ last_error=e,
294
+ ) from e
295
+
296
+ await asyncio.sleep(rule.delay(n - 1))
342
297
 
343
298
  async def send_liteserver_query(
344
299
  self,
@@ -459,7 +414,7 @@ class AdnlProvider:
459
414
  self,
460
415
  workchain: WorkchainID,
461
416
  shard: int,
462
- seqno: int = -1,
417
+ seqno: t.Optional[int] = None,
463
418
  lt: t.Optional[int] = None,
464
419
  utime: t.Optional[int] = None,
465
420
  *,
@@ -470,43 +425,133 @@ class AdnlProvider:
470
425
 
471
426
  :param workchain: Workchain identifier
472
427
  :param shard: Shard identifier
473
- :param seqno: Block seqno or -1 to ignore
428
+ :param seqno: Block sequence number
474
429
  :param lt: Logical time filter
475
430
  :param utime: UNIX time filter
476
431
  :param priority: Whether to use priority slot in the limiter
477
432
  :return: Tuple of BlockIdExt and deserialized Block
478
433
  """
479
434
  mode = 0
480
- if seqno != -1:
435
+ block_seqno = 0
436
+
437
+ if seqno is not None:
481
438
  mode = 1
439
+ block_seqno = seqno
482
440
  if lt is not None:
483
441
  mode = 2
484
442
  if utime is not None:
485
443
  mode = 4
486
444
 
487
445
  data = {
446
+ "mode": mode,
488
447
  "id": {
489
- "workchain": workchain.value,
448
+ "workchain": workchain,
490
449
  "shard": shard,
491
- "seqno": seqno,
450
+ "seqno": block_seqno,
492
451
  },
493
452
  "lt": lt,
494
- "mode": mode,
495
453
  "utime": utime,
496
454
  }
455
+
456
+ result = await self.send_liteserver_query(
457
+ "lookupBlock",
458
+ data=data,
459
+ priority=priority,
460
+ )
461
+
462
+ block_id = BlockIdExt.from_dict(result["id"])
463
+ header_proof = Cell.one_from_boc(result["header_proof"])
464
+ block = Block.deserialize(header_proof[0].begin_parse())
465
+
466
+ return block_id, block
467
+
468
+ async def get_block_header(
469
+ self,
470
+ block: BlockIdExt,
471
+ *,
472
+ priority: bool = False,
473
+ ) -> t.Tuple[BlockIdExt, Block]:
474
+ """
475
+ Fetch and deserialize block header by BlockIdExt.
476
+
477
+ :param block: BlockIdExt to query
478
+ :param priority: Whether to use priority slot in the limiter
479
+ :return: Tuple of BlockIdExt and deserialized Block
480
+ """
481
+ data = {"id": block.to_dict(), "mode": 0}
482
+
497
483
  result = await self.send_liteserver_query(
498
- method="lookupBlock",
484
+ "getBlockHeader",
499
485
  data=data,
500
486
  priority=priority,
501
487
  )
502
488
 
503
- cell = Cell.one_from_boc(result["header_proof"])
489
+ block_id = BlockIdExt.from_dict(result["id"])
490
+ header_proof = Cell.one_from_boc(result["header_proof"])
491
+ block_obj = Block.deserialize(header_proof[0].begin_parse())
492
+
493
+ return block_id, block_obj
494
+
495
+ async def get_block_transactions_ext(
496
+ self,
497
+ block: BlockIdExt,
498
+ count: int = 1024,
499
+ *,
500
+ priority: bool = False,
501
+ ) -> t.List[Transaction]:
502
+ """
503
+ Fetch extended block transactions list.
504
504
 
505
- return (
506
- BlockIdExt.from_dict(result["id"]),
507
- Block.deserialize(cell[0].begin_parse()),
505
+ :param block: Target block identifier
506
+ :param count: Maximum number of transactions per request
507
+ :param priority: Whether to use priority slot in the limiter
508
+ :return: List of deserialized Transaction objects
509
+ """
510
+ mode = 39
511
+ result = await self.send_liteserver_query(
512
+ method="listBlockTransactionsExt",
513
+ data={
514
+ "id": block.to_dict(),
515
+ "mode": mode,
516
+ "count": count,
517
+ "want_proof": b"",
518
+ },
519
+ priority=priority,
508
520
  )
509
521
 
522
+ transactions: t.List[Transaction] = []
523
+
524
+ def _append(result_data: dict) -> None:
525
+ if not result_data.get("transactions"):
526
+ return
527
+ for cell in Cell.from_boc(result_data["transactions"]):
528
+ transactions.append(Transaction.deserialize(cell.begin_parse()))
529
+
530
+ _append(result)
531
+
532
+ while result.get("incomplete"):
533
+ mode = 167
534
+ after = {
535
+ "account": transactions[-1].account_addr_hex,
536
+ "lt": transactions[-1].lt,
537
+ }
538
+
539
+ result = await self.send_liteserver_query(
540
+ method="listBlockTransactionsExt",
541
+ data={
542
+ "id": block.to_dict(),
543
+ "mode": mode,
544
+ "count": count,
545
+ "want_proof": b"",
546
+ "after": after,
547
+ },
548
+ priority=priority,
549
+ )
550
+
551
+ _append(result)
552
+
553
+ return transactions
554
+
510
555
  async def get_all_shards_info(
511
556
  self,
512
557
  block: t.Optional[BlockIdExt] = None,
@@ -586,13 +631,11 @@ class AdnlProvider:
586
631
 
587
632
  exit_code = result.get("exit_code")
588
633
  if exit_code is None:
589
- raise AdnlServerError(
590
- code=-1,
591
- message="RunGetMethod: missing `exit_code` in response",
592
- )
634
+ raise ProviderError("runSmcMethod: missing exit_code in response")
635
+
593
636
  if exit_code != 0:
594
637
  raise RunGetMethodError(
595
- address=address,
638
+ address=address.to_str(),
596
639
  method_name=method_name,
597
640
  exit_code=exit_code,
598
641
  )
@@ -676,7 +719,7 @@ class AdnlProvider:
676
719
  from_hash: str,
677
720
  *,
678
721
  priority: bool = False,
679
- ) -> list[Transaction]:
722
+ ) -> t.List[Transaction]:
680
723
  """
681
724
  Fetch a chain of transactions for an account.
682
725
 
@@ -689,7 +732,7 @@ class AdnlProvider:
689
732
  """
690
733
  if count > 16:
691
734
  raise ClientError(
692
- "`get_raw_transactions` supports up to 16 transactions per request"
735
+ "get_transactions supports up to 16 transactions per request"
693
736
  )
694
737
 
695
738
  data = {
@@ -707,13 +750,13 @@ class AdnlProvider:
707
750
  cells = Cell.from_boc(result["transactions"])
708
751
 
709
752
  prev_tr_hash = from_hash
710
- transactions: list[Transaction] = []
753
+ transactions: t.List[Transaction] = []
711
754
 
712
755
  for i, cell in enumerate(cells):
713
756
  curr_hash = cell.get_hash(0).hex()
714
757
  if curr_hash != prev_tr_hash:
715
758
  raise ClientError(
716
- "Transaction hash mismatch in `raw_get_transactions`: "
759
+ f"transaction hash mismatch: "
717
760
  f"expected {prev_tr_hash}, got {curr_hash}"
718
761
  )
719
762