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.
- {tonutils-2.0.1b7/tonutils.egg-info → tonutils-2.0.1b8}/PKG-INFO +1 -3
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/pyproject.toml +2 -4
- tonutils-2.0.1b8/tonutils/__init__.py +12 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/cli.py +1 -1
- tonutils-2.0.1b8/tonutils/clients/adnl/provider/config.py +35 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/__init__.py +3 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/telegram/tlb.py +1 -1
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/__init__.py +4 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/tlb.py +18 -16
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/v5.py +4 -4
- tonutils-2.0.1b8/tonutils/exceptions.py +155 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/types.py +22 -8
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/utils.py +47 -7
- {tonutils-2.0.1b7 → tonutils-2.0.1b8/tonutils.egg-info}/PKG-INFO +1 -3
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils.egg-info/SOURCES.txt +0 -7
- tonutils-2.0.1b7/tonutils/__init__.py +0 -17
- tonutils-2.0.1b7/tonutils/__meta__.py +0 -1
- tonutils-2.0.1b7/tonutils/clients/adnl/provider/config.py +0 -48
- tonutils-2.0.1b7/tonutils/exceptions.py +0 -228
- tonutils-2.0.1b7/tonutils/tonconnect/__init__.py +0 -0
- tonutils-2.0.1b7/tonutils/tonconnect/bridge/__init__.py +0 -0
- tonutils-2.0.1b7/tonutils/tonconnect/events.py +0 -0
- tonutils-2.0.1b7/tonutils/tonconnect/models/__init__.py +0 -0
- tonutils-2.0.1b7/tonutils/tonconnect/storage.py +0 -0
- tonutils-2.0.1b7/tonutils/tonconnect/tonconnect.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/LICENSE +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/README.md +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/setup.cfg +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/balancer.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/client.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/mixin.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/models.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/provider.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/transport.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/workers/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/workers/base.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/workers/pinger.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/workers/reader.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/provider/workers/updater.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/adnl/utils.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/base.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/balancer.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/chainstack.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/quicknode.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/tatum.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/tonapi.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/clients/toncenter.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/provider/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/provider/base.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/provider/models.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/provider/tonapi.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/provider/toncenter.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/http/utils.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/limiter.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/clients/protocol.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/base.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/codes.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/dns/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/dns/collection.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/dns/item.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/dns/methods.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/dns/tlb.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/jetton/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/jetton/master.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/jetton/methods.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/jetton/tlb.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/jetton/wallet.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/nft/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/nft/collection.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/nft/item.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/nft/methods.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/nft/tlb.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/opcodes.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/protocol.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/telegram/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/telegram/collection.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/telegram/item.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/telegram/methods.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/vanity/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/vanity/models.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/vanity/tlb.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/vanity/vanity.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/versions.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/base.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/configs.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/messages.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/methods.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/params.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/protocol.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/hw.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/pp.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/v1.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/v2.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/v3.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/contracts/wallet/versions/v4.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/py.typed +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/block_scanner/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/block_scanner/events.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/block_scanner/scanner.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/block_scanner/storage.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/status_monitor/__init__.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/status_monitor/console.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/status_monitor/models.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils/tools/status_monitor/monitor.py +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils.egg-info/dependency_links.txt +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils.egg-info/entry_points.txt +0 -0
- {tonutils-2.0.1b7 → tonutils-2.0.1b8}/tonutils.egg-info/requires.txt +0 -0
- {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.
|
|
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>=
|
|
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.
|
|
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"
|
|
@@ -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
|
-
|
|
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
|
|
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.
|
|
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
|
|
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.
|
|
235
|
+
return ctx ^ (self.network & 0xFFFFFFFF)
|
|
236
236
|
|
|
237
237
|
@classmethod
|
|
238
238
|
def unpack(
|
|
239
239
|
cls,
|
|
240
240
|
value: int,
|
|
241
|
-
|
|
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
|
|
247
|
+
:param network: Network identifier for XOR decoding
|
|
248
248
|
:return: Unpacked WalletV5SubwalletID instance
|
|
249
249
|
"""
|
|
250
|
-
ctx = (value ^
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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(
|
|
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
|
|
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(
|
|
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.
|
|
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
|
-
|
|
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,
|
|
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
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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
|
-
|
|
397
|
+
data = bytes.fromhex(payload)
|
|
392
398
|
except ValueError:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
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.
|
|
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 +0,0 @@
|
|
|
1
|
-
__version__ = "2.0.1b7"
|