tonutils 2.0.1b6__py3-none-any.whl → 2.0.1b8__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.
- tonutils/__init__.py +8 -13
- tonutils/cli.py +1 -1
- tonutils/clients/adnl/balancer.py +132 -355
- tonutils/clients/adnl/client.py +32 -202
- tonutils/clients/adnl/mixin.py +268 -0
- tonutils/clients/adnl/provider/config.py +7 -20
- tonutils/clients/adnl/provider/provider.py +61 -16
- tonutils/clients/adnl/provider/transport.py +13 -4
- tonutils/clients/adnl/provider/workers/pinger.py +1 -1
- tonutils/clients/adnl/utils.py +5 -5
- tonutils/clients/base.py +52 -92
- tonutils/clients/http/balancer.py +93 -90
- tonutils/clients/http/clients/tatum.py +1 -0
- tonutils/clients/http/clients/tonapi.py +12 -24
- tonutils/clients/http/clients/toncenter.py +15 -33
- tonutils/clients/http/provider/base.py +75 -60
- tonutils/clients/http/provider/models.py +1 -1
- tonutils/clients/http/provider/tonapi.py +0 -5
- tonutils/clients/http/provider/toncenter.py +4 -8
- tonutils/clients/protocol.py +6 -6
- tonutils/contracts/__init__.py +3 -0
- tonutils/contracts/base.py +32 -32
- tonutils/contracts/protocol.py +9 -9
- tonutils/contracts/telegram/tlb.py +1 -1
- tonutils/contracts/wallet/__init__.py +4 -0
- tonutils/contracts/wallet/base.py +5 -5
- tonutils/contracts/wallet/tlb.py +18 -16
- tonutils/contracts/wallet/versions/v5.py +6 -6
- tonutils/exceptions.py +45 -102
- tonutils/tools/block_scanner/__init__.py +5 -1
- tonutils/tools/block_scanner/scanner.py +1 -1
- tonutils/tools/status_monitor/monitor.py +6 -6
- tonutils/types.py +24 -10
- tonutils/utils.py +47 -7
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/METADATA +3 -20
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/RECORD +40 -46
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/WHEEL +1 -1
- tonutils/__meta__.py +0 -1
- tonutils/tonconnect/__init__.py +0 -0
- tonutils/tonconnect/bridge/__init__.py +0 -0
- tonutils/tonconnect/events.py +0 -0
- tonutils/tonconnect/models/__init__.py +0 -0
- tonutils/tonconnect/storage.py +0 -0
- tonutils/tonconnect/tonconnect.py +0 -0
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/entry_points.txt +0 -0
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/licenses/LICENSE +0 -0
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import typing as t
|
|
2
2
|
|
|
3
3
|
import aiohttp
|
|
4
|
-
from pydantic import BaseModel
|
|
5
4
|
|
|
6
5
|
from tonutils.clients.http.provider.base import HttpProvider
|
|
7
6
|
from tonutils.clients.http.provider.models import (
|
|
@@ -10,7 +9,7 @@ from tonutils.clients.http.provider.models import (
|
|
|
10
9
|
GetAddressInformationResult,
|
|
11
10
|
GetTransactionsResult,
|
|
12
11
|
RunGetMethodPayload,
|
|
13
|
-
|
|
12
|
+
RunGetMethodResult,
|
|
14
13
|
)
|
|
15
14
|
from tonutils.types import NetworkGlobalID, RetryPolicy
|
|
16
15
|
|
|
@@ -37,6 +36,7 @@ class ToncenterHttpProvider(HttpProvider):
|
|
|
37
36
|
}
|
|
38
37
|
base_url = base_url or urls[network]
|
|
39
38
|
headers = {**(headers or {}), **({"X-Api-Key": api_key} if api_key else {})}
|
|
39
|
+
|
|
40
40
|
super().__init__(
|
|
41
41
|
base_url=base_url,
|
|
42
42
|
session=session,
|
|
@@ -48,10 +48,6 @@ class ToncenterHttpProvider(HttpProvider):
|
|
|
48
48
|
retry_policy=retry_policy,
|
|
49
49
|
)
|
|
50
50
|
|
|
51
|
-
@staticmethod
|
|
52
|
-
def _model(model: t.Type[BaseModel], data: t.Any) -> t.Any:
|
|
53
|
-
return model.model_validate(data)
|
|
54
|
-
|
|
55
51
|
async def send_boc(
|
|
56
52
|
self,
|
|
57
53
|
payload: SendBocPayload,
|
|
@@ -116,9 +112,9 @@ class ToncenterHttpProvider(HttpProvider):
|
|
|
116
112
|
async def run_get_method(
|
|
117
113
|
self,
|
|
118
114
|
payload: RunGetMethodPayload,
|
|
119
|
-
) ->
|
|
115
|
+
) -> RunGetMethodResult:
|
|
120
116
|
return self._model(
|
|
121
|
-
|
|
117
|
+
RunGetMethodResult,
|
|
122
118
|
await self.send_http_request(
|
|
123
119
|
"POST",
|
|
124
120
|
"/runGetMethod",
|
tonutils/clients/protocol.py
CHANGED
|
@@ -6,7 +6,7 @@ from pytoniq_core import Cell, Transaction
|
|
|
6
6
|
|
|
7
7
|
from tonutils.types import (
|
|
8
8
|
AddressLike,
|
|
9
|
-
|
|
9
|
+
ContractInfo,
|
|
10
10
|
DNSCategory,
|
|
11
11
|
NetworkGlobalID,
|
|
12
12
|
ClientType,
|
|
@@ -40,19 +40,19 @@ class ClientProtocol(t.Protocol):
|
|
|
40
40
|
"""Underlying provider or transport backend."""
|
|
41
41
|
|
|
42
42
|
@property
|
|
43
|
-
def
|
|
43
|
+
def connected(self) -> bool:
|
|
44
44
|
"""Whether the client is connected and ready for requests."""
|
|
45
45
|
|
|
46
|
-
async def
|
|
46
|
+
async def send_message(self, boc: str) -> None:
|
|
47
47
|
"""Send an external message to the blockchain."""
|
|
48
48
|
|
|
49
|
-
async def
|
|
49
|
+
async def get_config(self) -> t.Dict[int, t.Any]:
|
|
50
50
|
"""Fetch global blockchain configuration."""
|
|
51
51
|
|
|
52
|
-
async def
|
|
52
|
+
async def get_info(
|
|
53
53
|
self,
|
|
54
54
|
address: AddressLike,
|
|
55
|
-
) ->
|
|
55
|
+
) -> ContractInfo:
|
|
56
56
|
"""Fetch basic contract state information."""
|
|
57
57
|
|
|
58
58
|
async def get_transactions(
|
tonutils/contracts/__init__.py
CHANGED
|
@@ -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",
|
tonutils/contracts/base.py
CHANGED
|
@@ -13,7 +13,7 @@ from tonutils.exceptions import (
|
|
|
13
13
|
StateNotLoadedError,
|
|
14
14
|
ProviderResponseError,
|
|
15
15
|
)
|
|
16
|
-
from tonutils.types import AddressLike,
|
|
16
|
+
from tonutils.types import AddressLike, ContractInfo, ContractState, WorkchainID
|
|
17
17
|
from tonutils.utils import to_cell
|
|
18
18
|
|
|
19
19
|
_R = t.TypeVar("_R")
|
|
@@ -61,7 +61,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
61
61
|
client: ClientProtocol,
|
|
62
62
|
address: Address,
|
|
63
63
|
state_init: t.Optional[StateInit] = None,
|
|
64
|
-
|
|
64
|
+
info: t.Optional[ContractInfo] = None,
|
|
65
65
|
) -> None:
|
|
66
66
|
"""
|
|
67
67
|
Initialize base contract wrapper.
|
|
@@ -69,12 +69,12 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
69
69
|
:param client: TON client for blockchain interactions
|
|
70
70
|
:param address: Contract address on the blockchain
|
|
71
71
|
:param state_init: Optional known StateInit (code and data)
|
|
72
|
-
:param
|
|
72
|
+
:param info: Optional preloaded on-chain contract state
|
|
73
73
|
"""
|
|
74
74
|
self._client = client
|
|
75
75
|
self._address = address
|
|
76
76
|
self._state_init = state_init
|
|
77
|
-
self.
|
|
77
|
+
self._info = info
|
|
78
78
|
|
|
79
79
|
@property
|
|
80
80
|
def client(self) -> ClientProtocol:
|
|
@@ -91,17 +91,6 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
91
91
|
"""Locally known StateInit for this contract, if any."""
|
|
92
92
|
return self._state_init
|
|
93
93
|
|
|
94
|
-
@property
|
|
95
|
-
def state_info(self) -> ContractStateInfo:
|
|
96
|
-
"""
|
|
97
|
-
Cached snapshot of the contract state.
|
|
98
|
-
|
|
99
|
-
:return: Contract state information
|
|
100
|
-
"""
|
|
101
|
-
if self._state_info is None:
|
|
102
|
-
raise StateNotLoadedError(self, missing="state_info")
|
|
103
|
-
return t.cast(ContractStateInfo, self._state_info)
|
|
104
|
-
|
|
105
94
|
@property
|
|
106
95
|
def state_data(self) -> _D:
|
|
107
96
|
"""
|
|
@@ -113,11 +102,22 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
113
102
|
"""
|
|
114
103
|
if not hasattr(self, "_data_model") or self._data_model is None:
|
|
115
104
|
raise ContractError(self, "No `_data_model` defined for contract class.")
|
|
116
|
-
if not (self.
|
|
105
|
+
if not (self._info and self._info.data):
|
|
117
106
|
raise StateNotLoadedError(self, missing="state_data")
|
|
118
|
-
cs = self.
|
|
107
|
+
cs = self._info.data.begin_parse()
|
|
119
108
|
return self._data_model.deserialize(cs)
|
|
120
109
|
|
|
110
|
+
@property
|
|
111
|
+
def info(self) -> ContractInfo:
|
|
112
|
+
"""
|
|
113
|
+
Cached snapshot of the contract state info.
|
|
114
|
+
|
|
115
|
+
:return: Contract state information
|
|
116
|
+
"""
|
|
117
|
+
if self._info is None:
|
|
118
|
+
raise StateNotLoadedError(self, missing="info")
|
|
119
|
+
return t.cast(ContractInfo, self._info)
|
|
120
|
+
|
|
121
121
|
@property
|
|
122
122
|
def balance(self) -> int:
|
|
123
123
|
"""
|
|
@@ -125,7 +125,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
125
125
|
|
|
126
126
|
:return: Balance from the latest known state
|
|
127
127
|
"""
|
|
128
|
-
return self.
|
|
128
|
+
return self.info.balance
|
|
129
129
|
|
|
130
130
|
@property
|
|
131
131
|
def state(self) -> ContractState:
|
|
@@ -134,7 +134,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
134
134
|
|
|
135
135
|
:return: One of ContractState enum values (ACTIVE, FROZEN, UNINIT, NONEXIST)
|
|
136
136
|
"""
|
|
137
|
-
return self.
|
|
137
|
+
return self.info.state
|
|
138
138
|
|
|
139
139
|
@property
|
|
140
140
|
def is_active(self) -> bool:
|
|
@@ -179,7 +179,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
179
179
|
|
|
180
180
|
:return: Transaction LT or None if unknown
|
|
181
181
|
"""
|
|
182
|
-
return self.
|
|
182
|
+
return self.info.last_transaction_lt
|
|
183
183
|
|
|
184
184
|
@property
|
|
185
185
|
def last_transaction_hash(self) -> t.Optional[str]:
|
|
@@ -188,7 +188,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
188
188
|
|
|
189
189
|
:return: Transaction hash as hex string or None if unknown
|
|
190
190
|
"""
|
|
191
|
-
return self.
|
|
191
|
+
return self.info.last_transaction_hash
|
|
192
192
|
|
|
193
193
|
@property
|
|
194
194
|
def code(self) -> t.Optional[Cell]:
|
|
@@ -197,7 +197,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
197
197
|
|
|
198
198
|
:return: Code cell or None if not available
|
|
199
199
|
"""
|
|
200
|
-
return self.
|
|
200
|
+
return self.info.code
|
|
201
201
|
|
|
202
202
|
@property
|
|
203
203
|
def data(self) -> t.Optional[Cell]:
|
|
@@ -206,36 +206,36 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
206
206
|
|
|
207
207
|
:return: Data cell or None if not available
|
|
208
208
|
"""
|
|
209
|
-
return self.
|
|
209
|
+
return self.info.data
|
|
210
210
|
|
|
211
211
|
@classmethod
|
|
212
|
-
async def
|
|
212
|
+
async def _load_info(
|
|
213
213
|
cls,
|
|
214
214
|
client: ClientProtocol,
|
|
215
215
|
address: Address,
|
|
216
|
-
) ->
|
|
216
|
+
) -> ContractInfo:
|
|
217
217
|
"""
|
|
218
218
|
Fetch contract state from the blockchain.
|
|
219
219
|
|
|
220
220
|
If the request fails (except rate limits), sets state to default empty state.
|
|
221
221
|
"""
|
|
222
222
|
try:
|
|
223
|
-
return await client.
|
|
223
|
+
return await client.get_info(address)
|
|
224
224
|
except ProviderResponseError as e:
|
|
225
225
|
if e.code in {429, 228, 5556}: # rate limit exceed
|
|
226
226
|
raise
|
|
227
|
-
return
|
|
227
|
+
return ContractInfo()
|
|
228
228
|
except (Exception,):
|
|
229
|
-
return
|
|
229
|
+
return ContractInfo()
|
|
230
230
|
|
|
231
231
|
async def refresh(self) -> None:
|
|
232
232
|
"""
|
|
233
233
|
Refresh contract state from the blockchain.
|
|
234
234
|
|
|
235
|
-
Fetches current contract information and updates the cached
|
|
235
|
+
Fetches current contract information and updates the cached info.
|
|
236
236
|
If the request fails (except rate limits), sets state to default empty state.
|
|
237
237
|
"""
|
|
238
|
-
self.
|
|
238
|
+
self._info = await self._load_info(self.client, self.address)
|
|
239
239
|
|
|
240
240
|
@classmethod
|
|
241
241
|
def from_state_init(
|
|
@@ -323,8 +323,8 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
323
323
|
if not load_state:
|
|
324
324
|
return cls(client, address)
|
|
325
325
|
|
|
326
|
-
|
|
327
|
-
return cls(client, address,
|
|
326
|
+
info = await cls._load_info(client, address)
|
|
327
|
+
return cls(client, address, info=info)
|
|
328
328
|
|
|
329
329
|
def __repr__(self) -> str:
|
|
330
330
|
return f"< Contract {self.__class__.__name__} address: {self.address} >"
|
tonutils/contracts/protocol.py
CHANGED
|
@@ -5,7 +5,7 @@ import typing as t
|
|
|
5
5
|
from pytoniq_core import Address, Cell, StateInit
|
|
6
6
|
|
|
7
7
|
from tonutils.clients.protocol import ClientProtocol
|
|
8
|
-
from tonutils.types import AddressLike,
|
|
8
|
+
from tonutils.types import AddressLike, ContractInfo, ContractState, WorkchainID
|
|
9
9
|
|
|
10
10
|
if t.TYPE_CHECKING:
|
|
11
11
|
from tonutils.contracts.versions import ContractVersion
|
|
@@ -48,21 +48,21 @@ class ContractProtocol(t.Protocol[_D]):
|
|
|
48
48
|
"""Locally known StateInit for this contract, if any."""
|
|
49
49
|
|
|
50
50
|
@property
|
|
51
|
-
def
|
|
51
|
+
def state_data(self) -> _D:
|
|
52
52
|
"""
|
|
53
|
-
|
|
53
|
+
Decoded on-chain data in typed form.
|
|
54
54
|
|
|
55
|
-
Implementations
|
|
56
|
-
|
|
55
|
+
Implementations must decode the current data cell from info
|
|
56
|
+
using the associated _data_model.
|
|
57
57
|
"""
|
|
58
58
|
|
|
59
59
|
@property
|
|
60
|
-
def
|
|
60
|
+
def info(self) -> ContractInfo:
|
|
61
61
|
"""
|
|
62
|
-
|
|
62
|
+
Cached snapshot of the contract state info.
|
|
63
63
|
|
|
64
|
-
Implementations
|
|
65
|
-
|
|
64
|
+
Implementations usually update this via refresh() or in constructors
|
|
65
|
+
that read on-chain data.
|
|
66
66
|
"""
|
|
67
67
|
|
|
68
68
|
@property
|
|
@@ -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",
|
|
@@ -22,7 +22,7 @@ from tonutils.contracts.wallet.tlb import BaseWalletData
|
|
|
22
22
|
from tonutils.exceptions import ContractError
|
|
23
23
|
from tonutils.types import (
|
|
24
24
|
AddressLike,
|
|
25
|
-
|
|
25
|
+
ContractInfo,
|
|
26
26
|
SendMode,
|
|
27
27
|
PublicKey,
|
|
28
28
|
PrivateKey,
|
|
@@ -61,7 +61,7 @@ class BaseWallet(BaseContract, WalletProtocol[_D, _C, _P], abc.ABC):
|
|
|
61
61
|
client: ClientProtocol,
|
|
62
62
|
address: Address,
|
|
63
63
|
state_init: t.Optional[StateInit] = None,
|
|
64
|
-
|
|
64
|
+
info: t.Optional[ContractInfo] = None,
|
|
65
65
|
config: t.Optional[_C] = None,
|
|
66
66
|
private_key: t.Optional[PrivateKey] = None,
|
|
67
67
|
) -> None:
|
|
@@ -71,7 +71,7 @@ class BaseWallet(BaseContract, WalletProtocol[_D, _C, _P], abc.ABC):
|
|
|
71
71
|
:param client: TON client for blockchain interactions
|
|
72
72
|
:param address: Wallet address on the blockchain
|
|
73
73
|
:param state_init: Optional StateInit (code and data)
|
|
74
|
-
:param
|
|
74
|
+
:param info: Optional preloaded contract state
|
|
75
75
|
:param config: Optional wallet configuration
|
|
76
76
|
:param private_key: Optional private key for signing transactions
|
|
77
77
|
"""
|
|
@@ -82,7 +82,7 @@ class BaseWallet(BaseContract, WalletProtocol[_D, _C, _P], abc.ABC):
|
|
|
82
82
|
if private_key is not None:
|
|
83
83
|
self._private_key = private_key
|
|
84
84
|
self._public_key = private_key.public_key
|
|
85
|
-
super().__init__(client, address, state_init,
|
|
85
|
+
super().__init__(client, address, state_init, info)
|
|
86
86
|
|
|
87
87
|
@property
|
|
88
88
|
def state_data(self) -> _D:
|
|
@@ -295,7 +295,7 @@ class BaseWallet(BaseContract, WalletProtocol[_D, _C, _P], abc.ABC):
|
|
|
295
295
|
:return: Signed external message that was sent
|
|
296
296
|
"""
|
|
297
297
|
external_msg = await self.build_external_message(messages, params)
|
|
298
|
-
await self.client.
|
|
298
|
+
await self.client.send_message(external_msg.as_hex)
|
|
299
299
|
return external_msg
|
|
300
300
|
|
|
301
301
|
async def transfer_message(
|
tonutils/contracts/wallet/tlb.py
CHANGED
|
@@ -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)
|
|
@@ -219,14 +219,14 @@ class WalletV5R1(
|
|
|
219
219
|
|
|
220
220
|
:return: Typed wallet data
|
|
221
221
|
"""
|
|
222
|
-
if not (self.
|
|
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
|
-
cs = self.
|
|
229
|
-
return self._data_model.deserialize(cs,
|
|
228
|
+
cs = self._info.data.begin_parse()
|
|
229
|
+
return self._data_model.deserialize(cs, network)
|
|
230
230
|
|
|
231
231
|
async def _build_msg_cell(
|
|
232
232
|
self,
|