tonutils 0.5.2__py3-none-any.whl → 0.6.0a1__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/{client → clients}/__init__.py +3 -11
- tonutils/clients/base.py +95 -0
- tonutils/clients/liteserver/__init__.py +3 -0
- tonutils/clients/liteserver/client.py +155 -0
- tonutils/clients/liteserver/stub.py +70 -0
- tonutils/clients/quicknode/__init__.py +3 -0
- tonutils/clients/quicknode/api.py +19 -0
- tonutils/clients/quicknode/client.py +20 -0
- tonutils/clients/tatum/__init__.py +3 -0
- tonutils/clients/tatum/api.py +28 -0
- tonutils/clients/tatum/client.py +24 -0
- tonutils/clients/tonapi/__init__.py +3 -0
- tonutils/clients/tonapi/api.py +93 -0
- tonutils/clients/tonapi/client.py +146 -0
- tonutils/clients/tonapi/models.py +34 -0
- tonutils/clients/toncenter/__init__.py +3 -0
- tonutils/clients/toncenter/api.py +91 -0
- tonutils/clients/toncenter/client.py +200 -0
- tonutils/clients/toncenter/models.py +70 -0
- tonutils/contracts/__init__.py +55 -0
- tonutils/contracts/base.py +155 -0
- tonutils/contracts/codes.py +30 -0
- tonutils/contracts/nft/__init__.py +21 -0
- tonutils/contracts/nft/collection.py +116 -0
- tonutils/contracts/nft/get_methods.py +124 -0
- tonutils/contracts/nft/item.py +119 -0
- tonutils/contracts/wallet/__init__.py +39 -0
- tonutils/contracts/wallet/base.py +300 -0
- tonutils/contracts/wallet/get_methods.py +145 -0
- tonutils/contracts/wallet/versions/__init__.py +45 -0
- tonutils/contracts/wallet/versions/hw.py +215 -0
- tonutils/contracts/wallet/versions/pp.py +88 -0
- tonutils/contracts/wallet/versions/v1.py +92 -0
- tonutils/contracts/wallet/versions/v2.py +81 -0
- tonutils/contracts/wallet/versions/v3.py +80 -0
- tonutils/contracts/wallet/versions/v4.py +102 -0
- tonutils/contracts/wallet/versions/v5.py +236 -0
- tonutils/exceptions.py +74 -25
- tonutils/protocols/__init__.py +9 -0
- tonutils/protocols/client.py +41 -0
- tonutils/protocols/contract.py +99 -0
- tonutils/protocols/wallet.py +116 -0
- tonutils/tonconnect/__init__.py +0 -11
- tonutils/types/__init__.py +187 -0
- tonutils/types/client.py +7 -0
- tonutils/types/common.py +39 -0
- tonutils/types/configs.py +79 -0
- tonutils/types/contract.py +79 -0
- tonutils/types/keystructs.py +91 -0
- tonutils/types/messages.py +142 -0
- tonutils/types/opcodes.py +15 -0
- tonutils/types/params.py +85 -0
- tonutils/types/stack.py +17 -0
- tonutils/types/tlb/__init__.py +87 -0
- tonutils/types/tlb/content.py +156 -0
- tonutils/types/tlb/contract.py +9 -0
- tonutils/types/tlb/msg.py +36 -0
- tonutils/types/tlb/nft.py +626 -0
- tonutils/types/tlb/text.py +53 -0
- tonutils/types/tlb/wallet.py +299 -0
- tonutils/utils/__init__.py +51 -0
- tonutils/utils/converters.py +58 -0
- tonutils/utils/msg_builders.py +82 -0
- tonutils/utils/parse_config.py +35 -0
- tonutils/utils/stack_codec.py +188 -0
- tonutils/utils/text_cipher.py +140 -0
- tonutils/utils/validations.py +23 -0
- tonutils/utils/value_utils.py +62 -0
- tonutils/utils/wallet_utils.py +55 -0
- {tonutils-0.5.2.dist-info → tonutils-0.6.0a1.dist-info}/METADATA +5 -10
- tonutils-0.6.0a1.dist-info/RECORD +76 -0
- {tonutils-0.5.2.dist-info → tonutils-0.6.0a1.dist-info}/WHEEL +1 -1
- {tonutils-0.5.2.dist-info → tonutils-0.6.0a1.dist-info}/licenses/LICENSE +1 -1
- tonutils/account.py +0 -32
- tonutils/cache.py +0 -82
- tonutils/client/_base.py +0 -292
- tonutils/client/lite.py +0 -163
- tonutils/client/quicknode.py +0 -33
- tonutils/client/tatum.py +0 -50
- tonutils/client/tonapi.py +0 -145
- tonutils/client/toncenter.py +0 -303
- tonutils/client/utils.py +0 -203
- tonutils/contract.py +0 -184
- tonutils/dns/__init__.py +0 -5
- tonutils/dns/categories.py +0 -15
- tonutils/dns/contract.py +0 -256
- tonutils/dns/op_codes.py +0 -1
- tonutils/dns/subdomain_collection/__init__.py +0 -5
- tonutils/dns/subdomain_collection/content.py +0 -18
- tonutils/dns/subdomain_collection/contract.py +0 -91
- tonutils/dns/subdomain_collection/data.py +0 -63
- tonutils/dns/subdomain_collection/op_codes.py +0 -5
- tonutils/dns/subdomain_manager/__init__.py +0 -5
- tonutils/dns/subdomain_manager/contract.py +0 -210
- tonutils/dns/subdomain_manager/data.py +0 -38
- tonutils/dns/subdomain_manager/op_codes.py +0 -1
- tonutils/dns/utils.py +0 -115
- tonutils/jetton/__init__.py +0 -15
- tonutils/jetton/content.py +0 -79
- tonutils/jetton/contract/__init__.py +0 -10
- tonutils/jetton/contract/base/__init__.py +0 -5
- tonutils/jetton/contract/base/master.py +0 -76
- tonutils/jetton/contract/stablecoin/__init__.py +0 -9
- tonutils/jetton/contract/stablecoin/master.py +0 -215
- tonutils/jetton/contract/stablecoin/op_codes.py +0 -17
- tonutils/jetton/contract/stablecoin/wallet.py +0 -134
- tonutils/jetton/contract/standard/__init__.py +0 -7
- tonutils/jetton/contract/standard/master.py +0 -141
- tonutils/jetton/contract/standard/op_codes.py +0 -11
- tonutils/jetton/contract/standard/wallet.py +0 -132
- tonutils/jetton/data.py +0 -165
- tonutils/jetton/dex/__init__.py +0 -0
- tonutils/jetton/dex/dedust/__init__.py +0 -5
- tonutils/jetton/dex/dedust/constants.py +0 -48
- tonutils/jetton/dex/dedust/factory.py +0 -362
- tonutils/jetton/dex/stonfi/__init__.py +0 -10
- tonutils/jetton/dex/stonfi/utils.py +0 -47
- tonutils/jetton/dex/stonfi/v1/__init__.py +0 -7
- tonutils/jetton/dex/stonfi/v1/pton/__init__.py +0 -5
- tonutils/jetton/dex/stonfi/v1/pton/constants.py +0 -19
- tonutils/jetton/dex/stonfi/v1/pton/pton.py +0 -78
- tonutils/jetton/dex/stonfi/v1/router/__init__.py +0 -5
- tonutils/jetton/dex/stonfi/v1/router/constants.py +0 -38
- tonutils/jetton/dex/stonfi/v1/router/router.py +0 -193
- tonutils/jetton/dex/stonfi/v2/__init__.py +0 -7
- tonutils/jetton/dex/stonfi/v2/pton/__init__.py +0 -5
- tonutils/jetton/dex/stonfi/v2/pton/constants.py +0 -21
- tonutils/jetton/dex/stonfi/v2/pton/pton.py +0 -102
- tonutils/jetton/dex/stonfi/v2/router/__init__.py +0 -5
- tonutils/jetton/dex/stonfi/v2/router/constants.py +0 -41
- tonutils/jetton/dex/stonfi/v2/router/router.py +0 -308
- tonutils/nft/__init__.py +0 -22
- tonutils/nft/content.py +0 -135
- tonutils/nft/contract/__init__.py +0 -0
- tonutils/nft/contract/base/__init__.py +0 -7
- tonutils/nft/contract/base/collection.py +0 -80
- tonutils/nft/contract/base/nft.py +0 -71
- tonutils/nft/contract/editable/__init__.py +0 -9
- tonutils/nft/contract/editable/collection.py +0 -341
- tonutils/nft/contract/editable/nft.py +0 -155
- tonutils/nft/contract/soulbound/__init__.py +0 -9
- tonutils/nft/contract/soulbound/collection.py +0 -277
- tonutils/nft/contract/soulbound/nft.py +0 -123
- tonutils/nft/contract/standard/__init__.py +0 -9
- tonutils/nft/contract/standard/collection.py +0 -257
- tonutils/nft/contract/standard/nft.py +0 -78
- tonutils/nft/data.py +0 -95
- tonutils/nft/marketplace/__init__.py +0 -0
- tonutils/nft/marketplace/getgems/__init__.py +0 -5
- tonutils/nft/marketplace/getgems/addresses.py +0 -8
- tonutils/nft/marketplace/getgems/contract/__init__.py +0 -5
- tonutils/nft/marketplace/getgems/contract/salev3r3.py +0 -161
- tonutils/nft/marketplace/getgems/data.py +0 -54
- tonutils/nft/marketplace/getgems/op_codes.py +0 -7
- tonutils/nft/op_codes.py +0 -19
- tonutils/nft/royalty_params.py +0 -29
- tonutils/tonconnect/connector.py +0 -699
- tonutils/tonconnect/models/__init__.py +0 -53
- tonutils/tonconnect/models/account.py +0 -57
- tonutils/tonconnect/models/chain.py +0 -10
- tonutils/tonconnect/models/device.py +0 -137
- tonutils/tonconnect/models/event.py +0 -33
- tonutils/tonconnect/models/proof.py +0 -80
- tonutils/tonconnect/models/request.py +0 -533
- tonutils/tonconnect/models/wallet.py +0 -248
- tonutils/tonconnect/provider/__init__.py +0 -5
- tonutils/tonconnect/provider/bridge.py +0 -581
- tonutils/tonconnect/provider/session.py +0 -104
- tonutils/tonconnect/storage/__init__.py +0 -7
- tonutils/tonconnect/storage/base.py +0 -39
- tonutils/tonconnect/storage/default.py +0 -40
- tonutils/tonconnect/tonconnect.py +0 -290
- tonutils/tonconnect/utils/__init__.py +0 -25
- tonutils/tonconnect/utils/exceptions.py +0 -140
- tonutils/tonconnect/utils/logger.py +0 -3
- tonutils/tonconnect/utils/verifiers.py +0 -255
- tonutils/tonconnect/utils/wallet_manager.py +0 -239
- tonutils/utils.py +0 -267
- tonutils/vanity/__init__.py +0 -5
- tonutils/vanity/contract.py +0 -35
- tonutils/vanity/data.py +0 -34
- tonutils/wallet/__init__.py +0 -31
- tonutils/wallet/contract/__init__.py +0 -24
- tonutils/wallet/contract/_base.py +0 -438
- tonutils/wallet/contract/highload.py +0 -505
- tonutils/wallet/contract/preprocessed.py +0 -291
- tonutils/wallet/contract/v2.py +0 -95
- tonutils/wallet/contract/v3.py +0 -94
- tonutils/wallet/contract/v4.py +0 -122
- tonutils/wallet/contract/v5.py +0 -193
- tonutils/wallet/data.py +0 -188
- tonutils/wallet/messages.py +0 -631
- tonutils/wallet/op_codes.py +0 -9
- tonutils/wallet/utils.py +0 -57
- tonutils-0.5.2.dist-info/RECORD +0 -131
- {tonutils-0.5.2.dist-info → tonutils-0.6.0a1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import typing as t
|
|
2
|
+
|
|
3
|
+
from pytoniq_core import (
|
|
4
|
+
Address,
|
|
5
|
+
Cell,
|
|
6
|
+
Slice,
|
|
7
|
+
StateInit,
|
|
8
|
+
begin_cell,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from .get_methods import NFTCollectionGetMethods
|
|
12
|
+
from ..base import BaseContract
|
|
13
|
+
from ...types import (
|
|
14
|
+
AddressLike,
|
|
15
|
+
NFTCollectionContent,
|
|
16
|
+
NFTCollectionData,
|
|
17
|
+
NFTCollectionVersion,
|
|
18
|
+
NFTItemVersion,
|
|
19
|
+
MetadataPrefix,
|
|
20
|
+
OnchainContent,
|
|
21
|
+
OffchainContent,
|
|
22
|
+
RoyaltyParams,
|
|
23
|
+
WorkchainID,
|
|
24
|
+
)
|
|
25
|
+
from ...utils import to_cell
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class BaseNFTCollection(BaseContract[NFTCollectionData]):
|
|
29
|
+
_data_model = NFTCollectionData
|
|
30
|
+
NFT_ITEM_VERSION: NFTItemVersion
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def owner_address(self) -> Address:
|
|
34
|
+
return self.state_data.owner_address
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def next_item_index(self) -> int:
|
|
38
|
+
return self.state_data.next_item_index
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def content(self) -> NFTCollectionContent:
|
|
42
|
+
return self.state_data.content
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def nft_item_code(self) -> Cell:
|
|
46
|
+
return self.state_data.nft_item_code
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def calculate_nft_item_address(
|
|
50
|
+
cls,
|
|
51
|
+
index: int,
|
|
52
|
+
nft_item_code: t.Union[Cell, str],
|
|
53
|
+
collection_address: AddressLike,
|
|
54
|
+
workchain: WorkchainID = WorkchainID.BASECHAIN,
|
|
55
|
+
) -> Address:
|
|
56
|
+
code = to_cell(nft_item_code)
|
|
57
|
+
data = begin_cell()
|
|
58
|
+
data.store_uint(index, 64)
|
|
59
|
+
data.store_address(collection_address)
|
|
60
|
+
state_init = StateInit(code=code, data=data.end_cell())
|
|
61
|
+
return Address((workchain.value, state_init.serialize().hash))
|
|
62
|
+
|
|
63
|
+
async def get_collection_data(self) -> t.Tuple[
|
|
64
|
+
int,
|
|
65
|
+
t.Union[OnchainContent, OffchainContent],
|
|
66
|
+
t.Optional[Address],
|
|
67
|
+
]:
|
|
68
|
+
method_result = await NFTCollectionGetMethods.get_collection_data(
|
|
69
|
+
client=self.client,
|
|
70
|
+
address=self.address,
|
|
71
|
+
)
|
|
72
|
+
content_cs: Slice = method_result[1].begin_parse()
|
|
73
|
+
return (
|
|
74
|
+
method_result[0],
|
|
75
|
+
(
|
|
76
|
+
OnchainContent.deserialize(content_cs, False)
|
|
77
|
+
if content_cs.load_uint(8) == MetadataPrefix.ONCHAIN
|
|
78
|
+
else OffchainContent.deserialize(content_cs, False)
|
|
79
|
+
),
|
|
80
|
+
method_result[2],
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
async def get_nft_content(
|
|
84
|
+
self,
|
|
85
|
+
index: int,
|
|
86
|
+
individual_nft_content: Cell,
|
|
87
|
+
) -> OffchainContent:
|
|
88
|
+
cell = await NFTCollectionGetMethods.get_nft_content(
|
|
89
|
+
client=self.client,
|
|
90
|
+
address=self.address,
|
|
91
|
+
index=index,
|
|
92
|
+
individual_nft_content=individual_nft_content,
|
|
93
|
+
)
|
|
94
|
+
return OffchainContent.deserialize(cell.begin_parse(), True)
|
|
95
|
+
|
|
96
|
+
async def get_nft_address_by_index(self, index: int) -> Address:
|
|
97
|
+
return await NFTCollectionGetMethods.get_nft_address_by_index(
|
|
98
|
+
client=self.client,
|
|
99
|
+
address=self.address,
|
|
100
|
+
index=index,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
async def royalty_params(self) -> RoyaltyParams:
|
|
104
|
+
royalty, denominator, address = await NFTCollectionGetMethods.royalty_params(
|
|
105
|
+
client=self.client,
|
|
106
|
+
address=self.address,
|
|
107
|
+
)
|
|
108
|
+
return RoyaltyParams(royalty, denominator, address)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class NFTCollectionStandard(BaseNFTCollection):
|
|
112
|
+
VERSION = NFTCollectionVersion.NFTCollectionStandard
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class NFTCollectionEditable(BaseNFTCollection):
|
|
116
|
+
VERSION = NFTCollectionVersion.NFTCollectionEditable
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import typing as t
|
|
2
|
+
|
|
3
|
+
from pytoniq_core import Address, Cell
|
|
4
|
+
|
|
5
|
+
from ...protocols import ClientProtocol
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class NFTCollectionGetMethods:
|
|
9
|
+
|
|
10
|
+
@classmethod
|
|
11
|
+
async def get_collection_data(
|
|
12
|
+
cls,
|
|
13
|
+
client: ClientProtocol,
|
|
14
|
+
address: Address,
|
|
15
|
+
) -> t.List[t.Any]:
|
|
16
|
+
method_result = await client.run_get_method(
|
|
17
|
+
address=address,
|
|
18
|
+
method_name="get_collection_data",
|
|
19
|
+
)
|
|
20
|
+
return method_result
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
async def get_nft_address_by_index(
|
|
24
|
+
cls,
|
|
25
|
+
client: ClientProtocol,
|
|
26
|
+
address: Address,
|
|
27
|
+
index: int,
|
|
28
|
+
) -> Address:
|
|
29
|
+
method_result = await client.run_get_method(
|
|
30
|
+
address=address,
|
|
31
|
+
method_name="get_nft_address_by_index",
|
|
32
|
+
stack=[index],
|
|
33
|
+
)
|
|
34
|
+
return method_result[0]
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
async def royalty_params(
|
|
38
|
+
cls,
|
|
39
|
+
client: ClientProtocol,
|
|
40
|
+
address: Address,
|
|
41
|
+
) -> t.List[t.Any]:
|
|
42
|
+
method_result = await client.run_get_method(
|
|
43
|
+
address=address,
|
|
44
|
+
method_name="royalty_params",
|
|
45
|
+
)
|
|
46
|
+
return method_result
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
async def get_nft_content(
|
|
50
|
+
cls,
|
|
51
|
+
client: ClientProtocol,
|
|
52
|
+
address: Address,
|
|
53
|
+
index: int,
|
|
54
|
+
individual_nft_content: Cell,
|
|
55
|
+
) -> Cell:
|
|
56
|
+
method_result = await client.run_get_method(
|
|
57
|
+
address=address,
|
|
58
|
+
method_name="get_nft_content",
|
|
59
|
+
stack=[index, individual_nft_content],
|
|
60
|
+
)
|
|
61
|
+
return method_result[0]
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
async def get_second_owner_address(
|
|
65
|
+
cls,
|
|
66
|
+
client: ClientProtocol,
|
|
67
|
+
address: Address,
|
|
68
|
+
) -> Address:
|
|
69
|
+
method_result = await client.run_get_method(
|
|
70
|
+
address=address,
|
|
71
|
+
method_name="get_second_owner_address",
|
|
72
|
+
)
|
|
73
|
+
return method_result[0]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class NFTItemGetMethods:
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
async def get_nft_data(
|
|
80
|
+
cls,
|
|
81
|
+
client: ClientProtocol,
|
|
82
|
+
address: Address,
|
|
83
|
+
) -> t.List[t.Any]:
|
|
84
|
+
method_result = await client.run_get_method(
|
|
85
|
+
address=address,
|
|
86
|
+
method_name="get_nft_data",
|
|
87
|
+
)
|
|
88
|
+
return method_result
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
async def get_editor(
|
|
92
|
+
cls,
|
|
93
|
+
client: ClientProtocol,
|
|
94
|
+
address: Address,
|
|
95
|
+
) -> t.Optional[Address]:
|
|
96
|
+
method_result = await client.run_get_method(
|
|
97
|
+
address=address,
|
|
98
|
+
method_name="get_editor",
|
|
99
|
+
)
|
|
100
|
+
return method_result[0]
|
|
101
|
+
|
|
102
|
+
@classmethod
|
|
103
|
+
async def get_authority_address(
|
|
104
|
+
cls,
|
|
105
|
+
client: ClientProtocol,
|
|
106
|
+
address: Address,
|
|
107
|
+
) -> t.Optional[Address]:
|
|
108
|
+
method_result = await client.run_get_method(
|
|
109
|
+
address=address,
|
|
110
|
+
method_name="get_authority_address",
|
|
111
|
+
)
|
|
112
|
+
return method_result[0]
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
async def get_revoked_time(
|
|
116
|
+
cls,
|
|
117
|
+
client: ClientProtocol,
|
|
118
|
+
address: Address,
|
|
119
|
+
) -> int:
|
|
120
|
+
method_result = await client.run_get_method(
|
|
121
|
+
address=address,
|
|
122
|
+
method_name="get_revoked_time",
|
|
123
|
+
)
|
|
124
|
+
return method_result[0]
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import typing as t
|
|
3
|
+
|
|
4
|
+
from pytoniq_core import Address, Slice
|
|
5
|
+
|
|
6
|
+
from .get_methods import NFTItemGetMethods
|
|
7
|
+
from ..base import BaseContract
|
|
8
|
+
from ...types import (
|
|
9
|
+
NFTItemEditableData,
|
|
10
|
+
NFTItemSoulboundData,
|
|
11
|
+
NFTItemStandardData,
|
|
12
|
+
NFTItemVersion,
|
|
13
|
+
OffchainItemContent,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
D = t.TypeVar(
|
|
17
|
+
"D",
|
|
18
|
+
bound=t.Union[
|
|
19
|
+
NFTItemEditableData,
|
|
20
|
+
NFTItemSoulboundData,
|
|
21
|
+
NFTItemStandardData,
|
|
22
|
+
],
|
|
23
|
+
)
|
|
24
|
+
C = t.TypeVar("C", bound=OffchainItemContent)
|
|
25
|
+
|
|
26
|
+
DStandard = t.TypeVar("DStandard", bound=NFTItemStandardData)
|
|
27
|
+
DEditable = t.TypeVar("DEditable", bound=NFTItemEditableData)
|
|
28
|
+
DSoulbound = t.TypeVar("DSoulbound", bound=NFTItemSoulboundData)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class BaseNFTItem(BaseContract[D], t.Generic[D, C], abc.ABC):
|
|
32
|
+
_data_model: t.Type[D]
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def state_data(self) -> D:
|
|
36
|
+
return super().state_data
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def index(self) -> int:
|
|
40
|
+
return self.state_data.index
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def owner_address(self) -> Address:
|
|
44
|
+
return self.state_data.owner_address
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def collection_address(self) -> Address:
|
|
48
|
+
return self.state_data.collection_address
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def content(self) -> C:
|
|
52
|
+
return self.state_data.content
|
|
53
|
+
|
|
54
|
+
async def get_nft_data(
|
|
55
|
+
self,
|
|
56
|
+
) -> t.Tuple[
|
|
57
|
+
bool,
|
|
58
|
+
int,
|
|
59
|
+
t.Optional[Address],
|
|
60
|
+
t.Optional[Address],
|
|
61
|
+
OffchainItemContent,
|
|
62
|
+
]:
|
|
63
|
+
method_result = await NFTItemGetMethods.get_nft_data(
|
|
64
|
+
client=self.client,
|
|
65
|
+
address=self.address,
|
|
66
|
+
)
|
|
67
|
+
content_cs: Slice = method_result[4].begin_parse()
|
|
68
|
+
return (
|
|
69
|
+
bool(method_result[0]),
|
|
70
|
+
method_result[1],
|
|
71
|
+
method_result[2],
|
|
72
|
+
method_result[3],
|
|
73
|
+
OffchainItemContent.deserialize(content_cs),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class NFTItemStandard(BaseNFTItem[DStandard, C]):
|
|
78
|
+
_data_model = NFTItemStandardData
|
|
79
|
+
VERSION = NFTItemVersion.NFTItemStandard
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class NFTItemEditable(BaseNFTItem[DEditable, C]):
|
|
83
|
+
_data_model = NFTItemEditableData
|
|
84
|
+
VERSION = NFTItemVersion.NFTItemStandard
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def editor_address(self) -> Address:
|
|
88
|
+
return self.state_data.editor_address
|
|
89
|
+
|
|
90
|
+
async def get_editor_address(self) -> t.Optional[Address]:
|
|
91
|
+
return await NFTItemGetMethods.get_editor(
|
|
92
|
+
client=self.client,
|
|
93
|
+
address=self.address,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class NFTItemSoulbound(BaseNFTItem[DSoulbound, C]):
|
|
98
|
+
_data_model = NFTItemSoulboundData
|
|
99
|
+
VERSION = NFTItemVersion.NFTItemStandard
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def authority_address(self) -> t.Optional[Address]:
|
|
103
|
+
return self.state_data.authority_address
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def revoked_at(self) -> int:
|
|
107
|
+
return self.state_data.revoked_at
|
|
108
|
+
|
|
109
|
+
async def get_authority_address(self) -> t.Optional[Address]:
|
|
110
|
+
return await NFTItemGetMethods.get_authority_address(
|
|
111
|
+
client=self.client,
|
|
112
|
+
address=self.address,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
async def get_revoked_time(self) -> int:
|
|
116
|
+
return await NFTItemGetMethods.get_revoked_time(
|
|
117
|
+
client=self.client,
|
|
118
|
+
address=self.address,
|
|
119
|
+
)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from .base import BaseWallet
|
|
2
|
+
from .get_methods import WalletGetMethods
|
|
3
|
+
|
|
4
|
+
from .versions import (
|
|
5
|
+
WalletHighloadV2,
|
|
6
|
+
WalletHighloadV3R1,
|
|
7
|
+
WalletPreprocessedV2,
|
|
8
|
+
WalletV1R1,
|
|
9
|
+
WalletV1R2,
|
|
10
|
+
WalletV1R3,
|
|
11
|
+
WalletV2R1,
|
|
12
|
+
WalletV2R2,
|
|
13
|
+
WalletV3R1,
|
|
14
|
+
WalletV3R2,
|
|
15
|
+
WalletV4R1,
|
|
16
|
+
WalletV4R2,
|
|
17
|
+
WalletV5Beta,
|
|
18
|
+
WalletV5R1,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"BaseWallet",
|
|
23
|
+
"WalletGetMethods",
|
|
24
|
+
"WalletHighloadV2",
|
|
25
|
+
"WalletHighloadV3R1",
|
|
26
|
+
"WalletPreprocessedV2",
|
|
27
|
+
"WalletV1R1",
|
|
28
|
+
"WalletV1R2",
|
|
29
|
+
"WalletV1R3",
|
|
30
|
+
"WalletV2R1",
|
|
31
|
+
"WalletV2R2",
|
|
32
|
+
"WalletV3R1",
|
|
33
|
+
"WalletV3R2",
|
|
34
|
+
"WalletV4R1",
|
|
35
|
+
"WalletV4R2",
|
|
36
|
+
"WalletV5Beta",
|
|
37
|
+
"WalletV5R1",
|
|
38
|
+
"get_methods",
|
|
39
|
+
]
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import abc
|
|
4
|
+
import typing as t
|
|
5
|
+
|
|
6
|
+
from pytoniq_core import (
|
|
7
|
+
Cell,
|
|
8
|
+
WalletMessage,
|
|
9
|
+
StateInit,
|
|
10
|
+
begin_cell,
|
|
11
|
+
Address,
|
|
12
|
+
)
|
|
13
|
+
from pytoniq_core.crypto.keys import (
|
|
14
|
+
mnemonic_to_private_key,
|
|
15
|
+
mnemonic_new,
|
|
16
|
+
)
|
|
17
|
+
from pytoniq_core.crypto.signature import sign_message
|
|
18
|
+
|
|
19
|
+
from ..base import BaseContract
|
|
20
|
+
from ..codes import CONTRACT_CODES
|
|
21
|
+
from ...exceptions import (
|
|
22
|
+
ContractError,
|
|
23
|
+
)
|
|
24
|
+
from ...protocols import (
|
|
25
|
+
ClientProtocol,
|
|
26
|
+
WalletProtocol,
|
|
27
|
+
)
|
|
28
|
+
from ...types import (
|
|
29
|
+
AddressLike,
|
|
30
|
+
BaseWalletConfig,
|
|
31
|
+
BaseWalletData,
|
|
32
|
+
BaseWalletParams,
|
|
33
|
+
PrivateKey,
|
|
34
|
+
PublicKey,
|
|
35
|
+
SendMode,
|
|
36
|
+
TransferJettonMessage,
|
|
37
|
+
TransferMessage,
|
|
38
|
+
TransferNFTMessage,
|
|
39
|
+
WorkchainID,
|
|
40
|
+
ContractStateInfo,
|
|
41
|
+
)
|
|
42
|
+
from ...utils import (
|
|
43
|
+
VALID_MNEMONIC_LENGTHS,
|
|
44
|
+
build_external_msg_any,
|
|
45
|
+
normalize_hash,
|
|
46
|
+
validate_mnemonic,
|
|
47
|
+
to_cell,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
D = t.TypeVar("D", bound=BaseWalletData)
|
|
51
|
+
C = t.TypeVar("C", bound=BaseWalletConfig)
|
|
52
|
+
P = t.TypeVar("P", bound=BaseWalletParams)
|
|
53
|
+
|
|
54
|
+
TWallet = t.TypeVar("TWallet", bound="BaseWallet[t.Any, t.Any, t.Any]")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class BaseWallet(BaseContract, WalletProtocol[D, C, P], abc.ABC):
|
|
58
|
+
_data_model: t.Type[D]
|
|
59
|
+
_config_model: t.Type[C]
|
|
60
|
+
_params_model: t.Type[P]
|
|
61
|
+
|
|
62
|
+
MAX_MESSAGES: t.ClassVar[int]
|
|
63
|
+
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
client: ClientProtocol,
|
|
67
|
+
address: Address,
|
|
68
|
+
state_init: t.Optional[StateInit] = None,
|
|
69
|
+
state_info: t.Optional[ContractStateInfo] = None,
|
|
70
|
+
config: t.Optional[C] = None,
|
|
71
|
+
private_key: t.Optional[PrivateKey] = None,
|
|
72
|
+
) -> None:
|
|
73
|
+
self._config = config
|
|
74
|
+
self._private_key: t.Optional[PrivateKey] = None
|
|
75
|
+
self._public_key: t.Optional[PublicKey] = None
|
|
76
|
+
|
|
77
|
+
if private_key is not None:
|
|
78
|
+
self._private_key = private_key
|
|
79
|
+
self._public_key = private_key.public_key
|
|
80
|
+
super().__init__(client, address, state_init, state_info)
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def state_data(self) -> D:
|
|
84
|
+
return super().state_data
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def config(self) -> C:
|
|
88
|
+
return t.cast(C, self._config)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def public_key(self) -> t.Optional[PublicKey]:
|
|
92
|
+
return self._public_key if self._public_key else None
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def private_key(self) -> t.Optional[PrivateKey]:
|
|
96
|
+
return self._private_key if self._private_key else None
|
|
97
|
+
|
|
98
|
+
@abc.abstractmethod
|
|
99
|
+
async def _build_msg_cell(
|
|
100
|
+
self,
|
|
101
|
+
messages: t.List[WalletMessage],
|
|
102
|
+
params: t.Optional[P] = None,
|
|
103
|
+
) -> Cell: ...
|
|
104
|
+
|
|
105
|
+
async def _build_sign_msg_cell(
|
|
106
|
+
self,
|
|
107
|
+
signing_msg: Cell,
|
|
108
|
+
signature: bytes,
|
|
109
|
+
) -> Cell:
|
|
110
|
+
cell = begin_cell()
|
|
111
|
+
cell.store_bytes(signature)
|
|
112
|
+
cell.store_cell(signing_msg)
|
|
113
|
+
return cell.end_cell()
|
|
114
|
+
|
|
115
|
+
async def _build_signed_msg_cell(
|
|
116
|
+
self,
|
|
117
|
+
messages: t.List[WalletMessage],
|
|
118
|
+
params: t.Optional[P] = None,
|
|
119
|
+
) -> Cell:
|
|
120
|
+
if self._private_key is None:
|
|
121
|
+
raise ContractError(
|
|
122
|
+
self,
|
|
123
|
+
f"Cannot sign message: "
|
|
124
|
+
f"`private_key` is not set for wallet `{self.VERSION.value}`.",
|
|
125
|
+
)
|
|
126
|
+
signed_msg = await self._build_msg_cell(messages, params)
|
|
127
|
+
signature = sign_message(signed_msg.hash, self._private_key.keypair.bytes)
|
|
128
|
+
return await self._build_sign_msg_cell(signed_msg, signature)
|
|
129
|
+
|
|
130
|
+
@classmethod
|
|
131
|
+
def from_private_key(
|
|
132
|
+
cls: t.Type[TWallet],
|
|
133
|
+
client: ClientProtocol,
|
|
134
|
+
private_key: PrivateKey,
|
|
135
|
+
workchain: WorkchainID = WorkchainID.BASECHAIN,
|
|
136
|
+
config: t.Optional[C] = None,
|
|
137
|
+
) -> TWallet:
|
|
138
|
+
config = config or cls._config_model()
|
|
139
|
+
cls._validate_config_type(config)
|
|
140
|
+
config.public_key = private_key.public_key
|
|
141
|
+
|
|
142
|
+
code = to_cell(CONTRACT_CODES[cls.VERSION])
|
|
143
|
+
data = cls._data_model(**config.to_dict()).serialize()
|
|
144
|
+
|
|
145
|
+
state_init = StateInit(code=code, data=data)
|
|
146
|
+
address = Address((workchain.value, state_init.serialize().hash))
|
|
147
|
+
return cls(client, address, state_init, None, config, private_key)
|
|
148
|
+
|
|
149
|
+
@classmethod
|
|
150
|
+
def from_mnemonic(
|
|
151
|
+
cls: t.Type[TWallet],
|
|
152
|
+
client: ClientProtocol,
|
|
153
|
+
mnemonic: t.Union[t.List[str], str],
|
|
154
|
+
validate: bool = True,
|
|
155
|
+
workchain: WorkchainID = WorkchainID.BASECHAIN,
|
|
156
|
+
config: t.Optional[C] = None,
|
|
157
|
+
) -> t.Tuple[TWallet, PublicKey, PrivateKey, t.List[str]]:
|
|
158
|
+
if isinstance(mnemonic, str):
|
|
159
|
+
mnemonic = mnemonic.strip().lower().split()
|
|
160
|
+
if validate:
|
|
161
|
+
validate_mnemonic(mnemonic)
|
|
162
|
+
|
|
163
|
+
pub_key_bytes, priv_key_bytes = mnemonic_to_private_key(mnemonic)
|
|
164
|
+
private_key = PrivateKey(priv_key_bytes)
|
|
165
|
+
public_key = PublicKey(pub_key_bytes)
|
|
166
|
+
|
|
167
|
+
wallet = cls.from_private_key(client, private_key, workchain, config)
|
|
168
|
+
return wallet, public_key, private_key, mnemonic
|
|
169
|
+
|
|
170
|
+
@classmethod
|
|
171
|
+
def create(
|
|
172
|
+
cls: t.Type[TWallet],
|
|
173
|
+
client: ClientProtocol,
|
|
174
|
+
mnemonic_length: int = 24,
|
|
175
|
+
workchain: WorkchainID = WorkchainID.BASECHAIN,
|
|
176
|
+
config: t.Optional[C] = None,
|
|
177
|
+
) -> t.Tuple[TWallet, PublicKey, PrivateKey, t.List[str]]:
|
|
178
|
+
cls._validate_mnemonic_length(mnemonic_length)
|
|
179
|
+
mnemonic = mnemonic_new(mnemonic_length)
|
|
180
|
+
return cls.from_mnemonic(client, mnemonic, True, workchain, config)
|
|
181
|
+
|
|
182
|
+
async def raw_transfer(
|
|
183
|
+
self,
|
|
184
|
+
messages: t.List[WalletMessage],
|
|
185
|
+
params: t.Optional[P] = None,
|
|
186
|
+
) -> str:
|
|
187
|
+
await self.refresh()
|
|
188
|
+
self._validate_message_count(messages)
|
|
189
|
+
self._validate_params_type(params)
|
|
190
|
+
|
|
191
|
+
body = await self._build_signed_msg_cell(messages, params)
|
|
192
|
+
state_init = self.state_init if not self.is_active else None
|
|
193
|
+
|
|
194
|
+
msg = build_external_msg_any(
|
|
195
|
+
dest=self.address,
|
|
196
|
+
body=body,
|
|
197
|
+
state_init=state_init,
|
|
198
|
+
)
|
|
199
|
+
msg_boc = msg.serialize().to_boc().hex()
|
|
200
|
+
normalized_hash = normalize_hash(msg)
|
|
201
|
+
|
|
202
|
+
await self.client.send_boc(msg_boc)
|
|
203
|
+
return normalized_hash
|
|
204
|
+
|
|
205
|
+
async def transfer(
|
|
206
|
+
self,
|
|
207
|
+
destination: AddressLike,
|
|
208
|
+
value: int,
|
|
209
|
+
body: t.Optional[t.Union[Cell, str]] = None,
|
|
210
|
+
state_init: t.Optional[StateInit] = None,
|
|
211
|
+
send_mode: t.Optional[t.Union[SendMode, int]] = None,
|
|
212
|
+
bounce: t.Optional[bool] = None,
|
|
213
|
+
params: t.Optional[P] = None,
|
|
214
|
+
) -> str:
|
|
215
|
+
message = TransferMessage(
|
|
216
|
+
destination=destination,
|
|
217
|
+
value=value,
|
|
218
|
+
body=body,
|
|
219
|
+
state_init=state_init,
|
|
220
|
+
send_mode=send_mode,
|
|
221
|
+
bounce=bounce,
|
|
222
|
+
)
|
|
223
|
+
return await self.transfer_message(message, params)
|
|
224
|
+
|
|
225
|
+
async def transfer_message(
|
|
226
|
+
self,
|
|
227
|
+
message: t.Union[
|
|
228
|
+
TransferMessage,
|
|
229
|
+
TransferNFTMessage,
|
|
230
|
+
TransferJettonMessage,
|
|
231
|
+
],
|
|
232
|
+
params: t.Optional[P] = None,
|
|
233
|
+
) -> str:
|
|
234
|
+
message = await message.to_wallet_msg(self)
|
|
235
|
+
return await self.raw_transfer([message], params)
|
|
236
|
+
|
|
237
|
+
async def batch_transfer_message(
|
|
238
|
+
self,
|
|
239
|
+
messages: t.List[
|
|
240
|
+
t.Union[
|
|
241
|
+
TransferMessage,
|
|
242
|
+
TransferNFTMessage,
|
|
243
|
+
TransferJettonMessage,
|
|
244
|
+
]
|
|
245
|
+
],
|
|
246
|
+
params: t.Optional[P] = None,
|
|
247
|
+
) -> str:
|
|
248
|
+
messages = [await m.to_wallet_msg(self) for m in messages]
|
|
249
|
+
return await self.raw_transfer(messages, params)
|
|
250
|
+
|
|
251
|
+
@classmethod
|
|
252
|
+
def _validate_config_type(
|
|
253
|
+
cls: t.Type[TWallet],
|
|
254
|
+
config: C,
|
|
255
|
+
) -> None:
|
|
256
|
+
if not isinstance(config, cls._config_model):
|
|
257
|
+
raise ContractError(
|
|
258
|
+
cls,
|
|
259
|
+
f"Invalid contract config type for `{cls.VERSION.value}`. "
|
|
260
|
+
f"Expected {cls._config_model.__name__}, "
|
|
261
|
+
f"got {type(config).__name__}.",
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
@classmethod
|
|
265
|
+
def _validate_params_type(
|
|
266
|
+
cls: t.Type[TWallet],
|
|
267
|
+
params: t.Optional[P] = None,
|
|
268
|
+
) -> None:
|
|
269
|
+
if params is not None and not isinstance(params, cls._params_model):
|
|
270
|
+
raise ContractError(
|
|
271
|
+
cls,
|
|
272
|
+
f"Invalid params type for `{cls.VERSION.value}`. "
|
|
273
|
+
f"Expected {cls._params_model.__name__}, "
|
|
274
|
+
f"got {type(params).__name__ if params is not None else 'None'}.",
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
@classmethod
|
|
278
|
+
def _validate_message_count(
|
|
279
|
+
cls: t.Type[TWallet],
|
|
280
|
+
messages: t.List[WalletMessage],
|
|
281
|
+
) -> None:
|
|
282
|
+
if len(messages) > cls.MAX_MESSAGES:
|
|
283
|
+
raise ContractError(
|
|
284
|
+
cls.__name__,
|
|
285
|
+
f"For `{cls.VERSION.value}`, "
|
|
286
|
+
f"maximum messages amount is {cls.MAX_MESSAGES}, "
|
|
287
|
+
f"but got {len(messages)}.",
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
@classmethod
|
|
291
|
+
def _validate_mnemonic_length(
|
|
292
|
+
cls: t.Type[TWallet],
|
|
293
|
+
mnemonic_length: int,
|
|
294
|
+
) -> None:
|
|
295
|
+
if mnemonic_length not in VALID_MNEMONIC_LENGTHS:
|
|
296
|
+
raise ContractError(
|
|
297
|
+
cls,
|
|
298
|
+
f"Invalid mnemonic length: {mnemonic_length}. "
|
|
299
|
+
f"Expected one of {VALID_MNEMONIC_LENGTHS}.",
|
|
300
|
+
)
|