tonutils 2.0.1b7__tar.gz → 2.0.1b8__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.
Files changed (115) hide show
  1. {tonutils-2.0.1b7/tonutils.egg-info → tonutils-2.0.1b8}/PKG-INFO +1 -3
  2. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/pyproject.toml +2 -4
  3. tonutils-2.0.1b8/tonutils/__init__.py +12 -0
  4. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/cli.py +1 -1
  5. tonutils-2.0.1b8/tonutils/clients/adnl/provider/config.py +35 -0
  6. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/__init__.py +3 -0
  7. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/telegram/tlb.py +1 -1
  8. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/__init__.py +4 -0
  9. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/tlb.py +18 -16
  10. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/v5.py +4 -4
  11. tonutils-2.0.1b8/tonutils/exceptions.py +155 -0
  12. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/types.py +22 -8
  13. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/utils.py +47 -7
  14. {tonutils-2.0.1b7 → tonutils-2.0.1b8/tonutils.egg-info}/PKG-INFO +1 -3
  15. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils.egg-info/SOURCES.txt +0 -7
  16. tonutils-2.0.1b7/tonutils/__init__.py +0 -17
  17. tonutils-2.0.1b7/tonutils/__meta__.py +0 -1
  18. tonutils-2.0.1b7/tonutils/clients/adnl/provider/config.py +0 -48
  19. tonutils-2.0.1b7/tonutils/exceptions.py +0 -228
  20. tonutils-2.0.1b7/tonutils/tonconnect/__init__.py +0 -0
  21. tonutils-2.0.1b7/tonutils/tonconnect/bridge/__init__.py +0 -0
  22. tonutils-2.0.1b7/tonutils/tonconnect/events.py +0 -0
  23. tonutils-2.0.1b7/tonutils/tonconnect/models/__init__.py +0 -0
  24. tonutils-2.0.1b7/tonutils/tonconnect/storage.py +0 -0
  25. tonutils-2.0.1b7/tonutils/tonconnect/tonconnect.py +0 -0
  26. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/LICENSE +0 -0
  27. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/README.md +0 -0
  28. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/setup.cfg +0 -0
  29. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/__init__.py +0 -0
  30. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/__init__.py +0 -0
  31. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/balancer.py +0 -0
  32. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/client.py +0 -0
  33. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/mixin.py +0 -0
  34. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/__init__.py +0 -0
  35. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/models.py +0 -0
  36. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/provider.py +0 -0
  37. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/transport.py +0 -0
  38. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/workers/__init__.py +0 -0
  39. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/workers/base.py +0 -0
  40. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/workers/pinger.py +0 -0
  41. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/workers/reader.py +0 -0
  42. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/workers/updater.py +0 -0
  43. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/utils.py +0 -0
  44. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/base.py +0 -0
  45. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/__init__.py +0 -0
  46. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/balancer.py +0 -0
  47. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/__init__.py +0 -0
  48. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/chainstack.py +0 -0
  49. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/quicknode.py +0 -0
  50. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/tatum.py +0 -0
  51. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/tonapi.py +0 -0
  52. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/toncenter.py +0 -0
  53. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/provider/__init__.py +0 -0
  54. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/provider/base.py +0 -0
  55. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/provider/models.py +0 -0
  56. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/provider/tonapi.py +0 -0
  57. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/provider/toncenter.py +0 -0
  58. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/utils.py +0 -0
  59. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/limiter.py +0 -0
  60. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/protocol.py +0 -0
  61. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/base.py +0 -0
  62. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/codes.py +0 -0
  63. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/dns/__init__.py +0 -0
  64. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/dns/collection.py +0 -0
  65. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/dns/item.py +0 -0
  66. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/dns/methods.py +0 -0
  67. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/dns/tlb.py +0 -0
  68. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/jetton/__init__.py +0 -0
  69. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/jetton/master.py +0 -0
  70. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/jetton/methods.py +0 -0
  71. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/jetton/tlb.py +0 -0
  72. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/jetton/wallet.py +0 -0
  73. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/nft/__init__.py +0 -0
  74. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/nft/collection.py +0 -0
  75. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/nft/item.py +0 -0
  76. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/nft/methods.py +0 -0
  77. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/nft/tlb.py +0 -0
  78. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/opcodes.py +0 -0
  79. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/protocol.py +0 -0
  80. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/telegram/__init__.py +0 -0
  81. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/telegram/collection.py +0 -0
  82. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/telegram/item.py +0 -0
  83. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/telegram/methods.py +0 -0
  84. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/vanity/__init__.py +0 -0
  85. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/vanity/models.py +0 -0
  86. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/vanity/tlb.py +0 -0
  87. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/vanity/vanity.py +0 -0
  88. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/versions.py +0 -0
  89. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/base.py +0 -0
  90. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/configs.py +0 -0
  91. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/messages.py +0 -0
  92. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/methods.py +0 -0
  93. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/params.py +0 -0
  94. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/protocol.py +0 -0
  95. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/__init__.py +0 -0
  96. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/hw.py +0 -0
  97. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/pp.py +0 -0
  98. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/v1.py +0 -0
  99. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/v2.py +0 -0
  100. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/v3.py +0 -0
  101. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/v4.py +0 -0
  102. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/py.typed +0 -0
  103. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/__init__.py +0 -0
  104. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/block_scanner/__init__.py +0 -0
  105. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/block_scanner/events.py +0 -0
  106. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/block_scanner/scanner.py +0 -0
  107. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/block_scanner/storage.py +0 -0
  108. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/status_monitor/__init__.py +0 -0
  109. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/status_monitor/console.py +0 -0
  110. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/status_monitor/models.py +0 -0
  111. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/status_monitor/monitor.py +0 -0
  112. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils.egg-info/dependency_links.txt +0 -0
  113. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils.egg-info/entry_points.txt +0 -0
  114. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils.egg-info/requires.txt +0 -0
  115. {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils.egg-info/top_level.txt +0 -0
@@ -1,13 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tonutils
3
- Version: 2.0.1b7
3
+ Version: 2.0.1b8
4
4
  Summary: Tonutils is a high-level, object-oriented Python library designed to facilitate seamless interactions with the TON blockchain.
5
5
  Author: nessshon
6
6
  Maintainer: nessshon
7
7
  License-Expression: MIT
8
8
  Project-URL: Homepage, https://github.com/nessshon/tonutils/
9
- Project-URL: Documentation, https://nessshon.github.io/tonutils/
10
- Project-URL: Repository, https://github.com/nessshon/tonutils/
11
9
  Project-URL: Examples, https://github.com/nessshon/tonutils/tree/main/examples/
12
10
  Keywords: AsyncIO,TON,TON blockchain,The Open Network,blockchain,crypto,smart contracts
13
11
  Classifier: Development Status :: 4 - Beta
@@ -1,5 +1,5 @@
1
1
  [build-system]
2
- requires = ["setuptools>=61"]
2
+ requires = ["setuptools>=80"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
@@ -46,8 +46,6 @@ license = "MIT"
46
46
 
47
47
  [project.urls]
48
48
  Homepage = "https://github.com/nessshon/tonutils/"
49
- Documentation = "https://nessshon.github.io/tonutils/"
50
- Repository = "https://github.com/nessshon/tonutils/"
51
49
  Examples = "https://github.com/nessshon/tonutils/tree/main/examples/"
52
50
 
53
51
  [tool.setuptools.packages.find]
@@ -60,4 +58,4 @@ tonutils = ["py.typed"]
60
58
  tonutils = "tonutils.cli:main"
61
59
 
62
60
  [tool.setuptools.dynamic]
63
- version = { attr = "tonutils.__meta__.__version__" }
61
+ version = { attr = "tonutils.__init__.__version__" }
@@ -0,0 +1,12 @@
1
+ # Copyright (c) 2024 Shon Ness
2
+ #
3
+ # This source code is licensed under the MIT License found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ __all__ = [
7
+ "__uri__",
8
+ "__version__",
9
+ ]
10
+
11
+ __version__ = "2.0.1b8"
12
+ __uri__ = "https://github.com/nessshon/tonutils"
@@ -2,7 +2,7 @@ import argparse
2
2
  import asyncio
3
3
  import typing as t
4
4
 
5
- from tonutils.__meta__ import __version__
5
+ from tonutils import __version__
6
6
  from tonutils.clients.adnl.provider.config import (
7
7
  get_mainnet_global_config,
8
8
  get_testnet_global_config,
@@ -0,0 +1,35 @@
1
+ from pydantic import ValidationError
2
+
3
+ from tonutils.clients.adnl.provider.models import GlobalConfig
4
+ from tonutils.utils import load_json
5
+
6
+
7
+ def load_global_config(source: str) -> GlobalConfig:
8
+ """
9
+ Fetch global configuration from source.
10
+
11
+ :return: Parsed GlobalConfig instance
12
+ """
13
+ try:
14
+ data = load_json(source)
15
+ return GlobalConfig.model_validate(data)
16
+ except ValidationError as e:
17
+ raise RuntimeError(f"Config validation failed: {e} ({source})") from e
18
+
19
+
20
+ def get_mainnet_global_config() -> GlobalConfig:
21
+ """
22
+ Fetch mainnet global configuration.
23
+
24
+ :return: Parsed GlobalConfig instance
25
+ """
26
+ return load_global_config("https://ton.org/global-config.json")
27
+
28
+
29
+ def get_testnet_global_config() -> GlobalConfig:
30
+ """
31
+ Fetch testnet global configuration.
32
+
33
+ :return: Parsed GlobalConfig instance
34
+ """
35
+ return load_global_config("https://ton.org/testnet-global-config.json")
@@ -127,6 +127,8 @@ from .vanity import (
127
127
  from .versions import ContractVersion
128
128
  from .wallet import (
129
129
  BaseMessageBuilder,
130
+ BaseWalletData,
131
+ BaseWalletParams,
130
132
  EncryptedTextCommentBody,
131
133
  ExternalMessage,
132
134
  InternalMessage,
@@ -194,6 +196,7 @@ __all__ = [
194
196
  "ALLOWED_DNS_ZONES",
195
197
  "BaseContract",
196
198
  "BaseMessageBuilder",
199
+ "BaseWalletData",
197
200
  "ChangeDNSRecordBody",
198
201
  "CONTRACT_CODES",
199
202
  "ContractProtocol",
@@ -296,7 +296,7 @@ class TeleItemContent(TlbScheme):
296
296
  """
297
297
  Initialize item content.
298
298
 
299
- :param nft_content: Off-chain NFT metadata (image, description, etc)
299
+ :param nft_content: Off-chain NFT metadata (image, description, etc.)
300
300
  :param dns: DNS records for the username/domain
301
301
  :param token_info: Token name and domain information
302
302
  """
@@ -34,6 +34,7 @@ from .methods import (
34
34
  seqno_get_method,
35
35
  )
36
36
  from .params import (
37
+ BaseWalletParams,
37
38
  WalletHighloadV2Params,
38
39
  WalletHighloadV3Params,
39
40
  WalletPreprocessedV2Params,
@@ -46,6 +47,7 @@ from .params import (
46
47
  )
47
48
  from .protocol import WalletProtocol
48
49
  from .tlb import (
50
+ BaseWalletData,
49
51
  EncryptedTextCommentBody,
50
52
  OutActionSendMsg,
51
53
  TextCommentBody,
@@ -81,6 +83,8 @@ __all__ = [
81
83
  "VALID_MNEMONIC_LENGTHS",
82
84
  "BaseMessageBuilder",
83
85
  "BaseWallet",
86
+ "BaseWalletData",
87
+ "BaseWalletParams",
84
88
  "EncryptedTextCommentBody",
85
89
  "ExternalMessage",
86
90
  "InternalMessage",
@@ -203,7 +203,7 @@ class WalletV5SubwalletID:
203
203
  subwallet_number: int = 0,
204
204
  workchain: WorkchainID = WorkchainID.BASECHAIN,
205
205
  version: int = 0,
206
- network_global_id: NetworkGlobalID = NetworkGlobalID.MAINNET,
206
+ network: NetworkGlobalID = NetworkGlobalID.MAINNET,
207
207
  ) -> None:
208
208
  """
209
209
  Initialize Wallet v5 subwallet ID.
@@ -211,19 +211,19 @@ class WalletV5SubwalletID:
211
211
  :param subwallet_number: Subwallet number (0-32767)
212
212
  :param workchain: Target workchain (default: BASECHAIN)
213
213
  :param version: Wallet version identifier (default: 0)
214
- :param network_global_id: Network identifier (default: MAINNET)
214
+ :param network: Network identifier (default: MAINNET)
215
215
  """
216
216
  self.subwallet_number = subwallet_number
217
217
  self.workchain = workchain
218
218
  self.version = version
219
- self.network_global_id = network_global_id
219
+ self.network = network
220
220
 
221
221
  def pack(self) -> int:
222
222
  """
223
223
  Pack subwallet ID components into 32-bit integer.
224
224
 
225
225
  Format: (1 << 31) | (workchain << 23) | (version << 15) | subwallet_number
226
- XORed with network_global_id for network isolation.
226
+ XORed with network for network isolation.
227
227
 
228
228
  :return: Packed 32-bit subwallet ID
229
229
  """
@@ -232,22 +232,22 @@ class WalletV5SubwalletID:
232
232
  ctx |= (self.workchain & 0xFF) << 23
233
233
  ctx |= (self.version & 0xFF) << 15
234
234
  ctx |= self.subwallet_number & 0x7FFF
235
- return ctx ^ (self.network_global_id & 0xFFFFFFFF)
235
+ return ctx ^ (self.network & 0xFFFFFFFF)
236
236
 
237
237
  @classmethod
238
238
  def unpack(
239
239
  cls,
240
240
  value: int,
241
- network_global_id: NetworkGlobalID,
241
+ network: NetworkGlobalID,
242
242
  ) -> WalletV5SubwalletID:
243
243
  """
244
244
  Unpack 32-bit integer into subwallet ID components.
245
245
 
246
246
  :param value: Packed 32-bit subwallet ID
247
- :param network_global_id: Network identifier for XOR decoding
247
+ :param network: Network identifier for XOR decoding
248
248
  :return: Unpacked WalletV5SubwalletID instance
249
249
  """
250
- ctx = (value ^ network_global_id) & 0xFFFFFFFF
250
+ ctx = (value ^ network) & 0xFFFFFFFF
251
251
 
252
252
  subwallet_number = ctx & 0x7FFF
253
253
  version = (ctx >> 15) & 0xFF
@@ -258,7 +258,7 @@ class WalletV5SubwalletID:
258
258
  subwallet_number=subwallet_number,
259
259
  workchain=WorkchainID(workchain),
260
260
  version=version,
261
- network_global_id=network_global_id,
261
+ network=network,
262
262
  )
263
263
 
264
264
  def __repr__(self) -> str:
@@ -298,7 +298,7 @@ class WalletV5BetaData(BaseWalletData):
298
298
 
299
299
  :param builder: Cell builder to store to
300
300
  """
301
- builder.store_int(self.subwallet_id.network_global_id, 32)
301
+ builder.store_int(self.subwallet_id.network, 32)
302
302
  builder.store_int(self.subwallet_id.workchain, 8)
303
303
  builder.store_uint(self.subwallet_id.version, 8)
304
304
  builder.store_uint(self.subwallet_id.subwallet_number, 32)
@@ -328,7 +328,7 @@ class WalletV5BetaData(BaseWalletData):
328
328
  :return: Loaded WalletV5SubwalletID
329
329
  """
330
330
  return WalletV5SubwalletID(
331
- network_global_id=NetworkGlobalID(cs.load_int(32)),
331
+ network=NetworkGlobalID(cs.load_int(32)),
332
332
  workchain=WorkchainID(cs.load_int(8)),
333
333
  version=cs.load_uint(8),
334
334
  subwallet_number=cs.load_uint(32),
@@ -398,20 +398,22 @@ class WalletV5Data(BaseWalletData):
398
398
  return cell.end_cell()
399
399
 
400
400
  @classmethod
401
- def deserialize(cls, cs: Slice, network_global_id: NetworkGlobalID) -> WalletV5Data:
401
+ def deserialize(
402
+ cls,
403
+ cs: Slice,
404
+ network: NetworkGlobalID = NetworkGlobalID.MAINNET,
405
+ ) -> WalletV5Data:
402
406
  """
403
407
  Deserialize wallet data from Cell slice.
404
408
 
405
409
  :param cs: Cell slice to deserialize from
406
- :param network_global_id: Network ID for unpacking subwallet_id
410
+ :param network: Network ID for unpacking subwallet_id
407
411
  :return: Deserialized WalletV5Data instance
408
412
  """
409
413
  return cls(
410
414
  is_signature_allowed=cs.load_bool(),
411
415
  seqno=cs.load_uint(32),
412
- subwallet_id=WalletV5SubwalletID.unpack(
413
- cs.load_uint(32), network_global_id
414
- ),
416
+ subwallet_id=WalletV5SubwalletID.unpack(cs.load_uint(32), network),
415
417
  public_key=PublicKey(cs.load_bytes(32)),
416
418
  plugins=cs.load_maybe_ref(),
417
419
  )
@@ -63,7 +63,7 @@ class _WalletV5(
63
63
  cls._validate_config_type(config)
64
64
 
65
65
  if config.subwallet_id is None:
66
- config.subwallet_id = WalletV5SubwalletID(network_global_id=client.network)
66
+ config.subwallet_id = WalletV5SubwalletID(network=client.network)
67
67
 
68
68
  return super().from_private_key(client, private_key, workchain, config)
69
69
 
@@ -163,7 +163,7 @@ class WalletV5Beta(
163
163
 
164
164
  cell = begin_cell()
165
165
  cell.store_uint(params.op_code, 32)
166
- cell.store_int(subwallet_id.network_global_id, 32)
166
+ cell.store_int(subwallet_id.network, 32)
167
167
  cell.store_int(subwallet_id.workchain, 8)
168
168
  cell.store_uint(subwallet_id.version, 8)
169
169
  cell.store_uint(subwallet_id.subwallet_number, 32)
@@ -222,11 +222,11 @@ class WalletV5R1(
222
222
  if not (self._info and self._info.data):
223
223
  raise StateNotLoadedError(self, missing="state_data")
224
224
 
225
- network_global_id = (
225
+ network = (
226
226
  NetworkGlobalID.TESTNET if self.client.network else NetworkGlobalID.MAINNET
227
227
  )
228
228
  cs = self._info.data.begin_parse()
229
- return self._data_model.deserialize(cs, network_global_id)
229
+ return self._data_model.deserialize(cs, network)
230
230
 
231
231
  async def _build_msg_cell(
232
232
  self,
@@ -0,0 +1,155 @@
1
+ import asyncio
2
+ import typing as t
3
+
4
+ __all__ = [
5
+ "TonutilsError",
6
+ "TransportError",
7
+ "ProviderError",
8
+ "ClientError",
9
+ "ContractError",
10
+ "BalancerError",
11
+ "NotConnectedError",
12
+ "ProviderTimeoutError",
13
+ "ProviderResponseError",
14
+ "RetryLimitError",
15
+ "RunGetMethodError",
16
+ "StateNotLoadedError",
17
+ "CDN_CHALLENGE_MARKERS",
18
+ ]
19
+
20
+
21
+ class TonutilsError(Exception):
22
+ """Base exception for tonutils."""
23
+
24
+
25
+ class TransportError(TonutilsError):
26
+ """Transport-level failure (connect/handshake/send/recv)."""
27
+
28
+ def __init__(self, *, endpoint: str, operation: str, reason: str) -> None:
29
+ self.endpoint = endpoint
30
+ self.operation = operation
31
+ self.reason = reason
32
+ super().__init__(f"{operation} failed: {reason} ({endpoint})")
33
+
34
+
35
+ class ProviderError(TonutilsError):
36
+ """Provider-level failure (protocol/parsing/backend/state)."""
37
+
38
+
39
+ class ClientError(TonutilsError):
40
+ """Client misuse, validation errors, or unsupported operations."""
41
+
42
+
43
+ class BalancerError(TonutilsError):
44
+ """Balancer failure (no alive backends, failover exhausted)."""
45
+
46
+
47
+ class NotConnectedError(TonutilsError, RuntimeError):
48
+ """Raised when an operation requires an active connection."""
49
+
50
+ def __init__(
51
+ self,
52
+ *,
53
+ component: str = "client",
54
+ endpoint: t.Optional[str] = None,
55
+ operation: t.Optional[str] = None,
56
+ ) -> None:
57
+ self.component = component
58
+ self.endpoint = endpoint
59
+ self.operation = operation
60
+
61
+ op = f"cannot `{operation}`: " if operation else ""
62
+ where = f" ({endpoint})" if endpoint else ""
63
+ super().__init__(f"{op}{component} is not connected{where}")
64
+
65
+
66
+ class ProviderTimeoutError(ProviderError, asyncio.TimeoutError):
67
+ """Provider operation exceeded its timeout."""
68
+
69
+ def __init__(self, *, timeout: float, endpoint: str, operation: str) -> None:
70
+ self.timeout = float(timeout)
71
+ self.endpoint = endpoint
72
+ self.operation = operation
73
+ super().__init__(f"{operation} timed out after {self.timeout}s ({endpoint})")
74
+
75
+
76
+ class ProviderResponseError(ProviderError):
77
+ """Backend returned an error response."""
78
+
79
+ def __init__(self, *, code: int, message: str, endpoint: str) -> None:
80
+ self.code = int(code)
81
+ self.message = message
82
+ self.endpoint = endpoint
83
+ super().__init__(f"request failed: {self.code} {self.message} ({endpoint})")
84
+
85
+
86
+ class RetryLimitError(ProviderError):
87
+ """Retry policy exhausted."""
88
+
89
+ def __init__(
90
+ self,
91
+ attempts: int,
92
+ max_attempts: int,
93
+ last_error: ProviderError,
94
+ ) -> None:
95
+ self.attempts = int(attempts)
96
+ self.max_attempts = int(max_attempts)
97
+ self.last_error = last_error
98
+ ratio = f"{self.attempts}/{self.max_attempts}"
99
+ super().__init__(f"retry limit reached {ratio}: {last_error}")
100
+
101
+
102
+ class ContractError(ClientError):
103
+ """Contract wrapper operation failed."""
104
+
105
+ def __init__(self, target: t.Any, details: str) -> None:
106
+ self.target = target
107
+ self.details = details
108
+
109
+ if isinstance(target, type):
110
+ name = target.__name__
111
+ else:
112
+ name = target.__class__.__name__
113
+
114
+ super().__init__(f"{name} failed: {details}")
115
+
116
+
117
+ class StateNotLoadedError(ContractError):
118
+ """Contract wrapper requires state that is not loaded."""
119
+
120
+ def __init__(self, contract: t.Any, *, missing: str) -> None:
121
+ self.missing = missing
122
+ name = contract.__class__.__name__
123
+ super().__init__(contract, f"{missing} is not loaded. Call {name}.refresh().")
124
+
125
+
126
+ class RunGetMethodError(ClientError):
127
+ """Contract get-method returned a non-zero TVM exit code."""
128
+
129
+ def __init__(self, *, address: str, exit_code: int, method_name: str) -> None:
130
+ self.address = address
131
+ self.exit_code = int(exit_code)
132
+ self.method_name = method_name
133
+ super().__init__(
134
+ f"get-method `{method_name}` failed: exit code {self.exit_code} ({address})"
135
+ )
136
+
137
+
138
+ CDN_CHALLENGE_MARKERS: t.Dict[str, str] = {
139
+ # Cloudflare
140
+ "cloudflare": "Cloudflare protection triggered or blocked the request.",
141
+ "cf-ray": "Cloudflare intermediate error (cf-ray header detected).",
142
+ "just a moment": "Cloudflare browser verification page.",
143
+ "checking your browser": "Cloudflare browser verification page.",
144
+ "attention required": "Cloudflare challenge page.",
145
+ "captcha": "Cloudflare CAPTCHA challenge.",
146
+ # Other CDNs / proxies
147
+ "akamai": "Akamai CDN blocked or intercepted the request.",
148
+ "fastly": "Fastly CDN error response detected.",
149
+ "varnish": "Varnish cache/CDN interference.",
150
+ "nginx": "Reverse proxy (nginx) error response.",
151
+ # Upstream failures
152
+ "502 bad gateway": "Bad gateway from upstream or proxy.",
153
+ "503 service unavailable": "Service temporarily unavailable (proxy or CDN).",
154
+ "ddos": "Possible DDoS protection or mitigation page.",
155
+ }
@@ -1,7 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import base64
4
+ import re
4
5
  import typing as t
6
+ from contextlib import suppress
5
7
  from dataclasses import dataclass
6
8
  from enum import Enum
7
9
 
@@ -280,22 +282,34 @@ class Binary:
280
282
  return self._size
281
283
 
282
284
  def _parse(self, value: t.Any) -> bytes:
283
- """Parse input value into bytes."""
284
285
  if isinstance(value, bytes):
285
286
  return value
286
287
  if isinstance(value, int):
287
288
  length = max(1, (value.bit_length() + 7) // 8)
288
289
  return value.to_bytes(length, "big")
290
+
289
291
  if isinstance(value, str):
290
292
  s = value.strip()
293
+
294
+ # 0x... hex
291
295
  if s.lower().startswith("0x"):
292
- return int(s, 16).to_bytes(self._size, "big")
293
- try:
294
- return base64.b64decode(s)
295
- except (Exception,):
296
- n = int(s, 10)
297
- length = max(1, (n.bit_length() + 7) // 8)
298
- return n.to_bytes(length, "big")
296
+ return bytes.fromhex(s[2:])
297
+
298
+ # plain hex (common case for publicKey)
299
+ if len(s) % 2 == 0 and re.compile(r"^[0-9a-fA-F]+$").fullmatch(s):
300
+ if len(s) == self._size * 2:
301
+ return bytes.fromhex(s)
302
+
303
+ # base64 (strict)
304
+ with suppress(Exception):
305
+ b = base64.b64decode(s, validate=True)
306
+ return b
307
+
308
+ # decimal int as string fallback
309
+ n = int(s, 10)
310
+ length = max(1, (n.bit_length() + 7) // 8)
311
+ return n.to_bytes(length, "big")
312
+
299
313
  raise ValueError(f"Invalid binary type: {type(value).__name__}.")
300
314
 
301
315
  @property
@@ -5,9 +5,13 @@ import binascii
5
5
  import decimal
6
6
  import hashlib
7
7
  import hmac
8
+ import json
8
9
  import os
9
10
  import time
10
11
  import typing as t
12
+ import urllib.request
13
+ from pathlib import Path
14
+ from urllib.error import HTTPError, URLError
11
15
 
12
16
  from Cryptodome.Cipher import AES
13
17
  from nacl.bindings import (
@@ -40,6 +44,7 @@ __all__ = [
40
44
  "cell_to_hex",
41
45
  "decode_dns_name",
42
46
  "encode_dns_name",
47
+ "load_json",
43
48
  "maybe_stack_addr",
44
49
  "norm_stack_cell",
45
50
  "norm_stack_num",
@@ -387,15 +392,15 @@ class TextCipher:
387
392
  if isinstance(payload, bytes):
388
393
  return payload[:32], payload[32:48], payload[48:]
389
394
  elif isinstance(payload, str):
395
+ # Try hex first; if that fails, try base64.
390
396
  try:
391
- payload = bytes.fromhex(payload)
397
+ data = bytes.fromhex(payload)
392
398
  except ValueError:
393
- pass
394
- try:
395
- payload = base64.b64decode(payload, validate=True)
396
- except (binascii.Error, ValueError):
397
- raise ValueError("Invalid payload encoding: not hex or base64.")
398
- return payload[:32], payload[32:48], payload[48:]
399
+ try:
400
+ data = base64.b64decode(payload, validate=True)
401
+ except (binascii.Error, ValueError):
402
+ raise ValueError("Invalid payload encoding: not hex or base64.")
403
+ return data[:32], data[32:48], data[48:]
399
404
 
400
405
  cell = EncryptedTextCommentBody.deserialize(payload.begin_parse())
401
406
  return cell.pub_xor, cell.msg_key, cell.ciphertext
@@ -501,3 +506,38 @@ class TextCipher:
501
506
 
502
507
  comment = dec_data[padding_size:]
503
508
  return comment.decode()
509
+
510
+
511
+ def load_json(source: str, timeout: float = 5.0) -> t.Any:
512
+ """
513
+ Load and parse JSON from a URL or a local file.
514
+
515
+ :param source: URL or file path
516
+ :param timeout: Network timeout in seconds
517
+ :return: Parsed JSON object
518
+ """
519
+ try:
520
+ if source.startswith(("http://", "https://")):
521
+ req = urllib.request.Request(
522
+ source,
523
+ method="GET",
524
+ headers={
525
+ "User-Agent": "tonutils (+https://github.com/nessshon/tonutils)",
526
+ "Accept": "application/json,text/plain,*/*",
527
+ },
528
+ )
529
+ with urllib.request.urlopen(req, timeout=timeout) as r:
530
+ return json.loads(r.read().decode("utf-8"))
531
+
532
+ return json.loads(Path(source).read_text(encoding="utf-8"))
533
+
534
+ except HTTPError as e:
535
+ raise RuntimeError(f"JSON fetch failed: {e} ({source})") from e
536
+ except URLError as e:
537
+ raise RuntimeError(f"JSON fetch failed: {e.reason} ({source})") from e
538
+ except json.JSONDecodeError as e:
539
+ raise RuntimeError(f"JSON is invalid: {e.msg} ({source})") from e
540
+ except OSError as e:
541
+ raise RuntimeError(f"JSON read failed: {e} ({source})") from e
542
+ except Exception as e:
543
+ raise RuntimeError(f"JSON load failed: {e} ({source})") from e
@@ -1,13 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tonutils
3
- Version: 2.0.1b7
3
+ Version: 2.0.1b8
4
4
  Summary: Tonutils is a high-level, object-oriented Python library designed to facilitate seamless interactions with the TON blockchain.
5
5
  Author: nessshon
6
6
  Maintainer: nessshon
7
7
  License-Expression: MIT
8
8
  Project-URL: Homepage, https://github.com/nessshon/tonutils/
9
- Project-URL: Documentation, https://nessshon.github.io/tonutils/
10
- Project-URL: Repository, https://github.com/nessshon/tonutils/
11
9
  Project-URL: Examples, https://github.com/nessshon/tonutils/tree/main/examples/
12
10
  Keywords: AsyncIO,TON,TON blockchain,The Open Network,blockchain,crypto,smart contracts
13
11
  Classifier: Development Status :: 4 - Beta
@@ -2,7 +2,6 @@ LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
4
  tonutils/__init__.py
5
- tonutils/__meta__.py
6
5
  tonutils/cli.py
7
6
  tonutils/exceptions.py
8
7
  tonutils/py.typed
@@ -93,12 +92,6 @@ tonutils/contracts/wallet/versions/v2.py
93
92
  tonutils/contracts/wallet/versions/v3.py
94
93
  tonutils/contracts/wallet/versions/v4.py
95
94
  tonutils/contracts/wallet/versions/v5.py
96
- tonutils/tonconnect/__init__.py
97
- tonutils/tonconnect/events.py
98
- tonutils/tonconnect/storage.py
99
- tonutils/tonconnect/tonconnect.py
100
- tonutils/tonconnect/bridge/__init__.py
101
- tonutils/tonconnect/models/__init__.py
102
95
  tonutils/tools/__init__.py
103
96
  tonutils/tools/block_scanner/__init__.py
104
97
  tonutils/tools/block_scanner/events.py
@@ -1,17 +0,0 @@
1
- from . import (
2
- clients,
3
- contracts,
4
- exceptions,
5
- types,
6
- utils,
7
- )
8
- from .__meta__ import __version__
9
-
10
- __all__ = [
11
- "__version__",
12
- "clients",
13
- "contracts",
14
- "exceptions",
15
- "types",
16
- "utils",
17
- ]
@@ -1 +0,0 @@
1
- __version__ = "2.0.1b7"