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.
Files changed (196) hide show
  1. tonutils/{client → clients}/__init__.py +3 -11
  2. tonutils/clients/base.py +95 -0
  3. tonutils/clients/liteserver/__init__.py +3 -0
  4. tonutils/clients/liteserver/client.py +155 -0
  5. tonutils/clients/liteserver/stub.py +70 -0
  6. tonutils/clients/quicknode/__init__.py +3 -0
  7. tonutils/clients/quicknode/api.py +19 -0
  8. tonutils/clients/quicknode/client.py +20 -0
  9. tonutils/clients/tatum/__init__.py +3 -0
  10. tonutils/clients/tatum/api.py +28 -0
  11. tonutils/clients/tatum/client.py +24 -0
  12. tonutils/clients/tonapi/__init__.py +3 -0
  13. tonutils/clients/tonapi/api.py +93 -0
  14. tonutils/clients/tonapi/client.py +146 -0
  15. tonutils/clients/tonapi/models.py +34 -0
  16. tonutils/clients/toncenter/__init__.py +3 -0
  17. tonutils/clients/toncenter/api.py +91 -0
  18. tonutils/clients/toncenter/client.py +200 -0
  19. tonutils/clients/toncenter/models.py +70 -0
  20. tonutils/contracts/__init__.py +55 -0
  21. tonutils/contracts/base.py +155 -0
  22. tonutils/contracts/codes.py +30 -0
  23. tonutils/contracts/nft/__init__.py +21 -0
  24. tonutils/contracts/nft/collection.py +116 -0
  25. tonutils/contracts/nft/get_methods.py +124 -0
  26. tonutils/contracts/nft/item.py +119 -0
  27. tonutils/contracts/wallet/__init__.py +39 -0
  28. tonutils/contracts/wallet/base.py +300 -0
  29. tonutils/contracts/wallet/get_methods.py +145 -0
  30. tonutils/contracts/wallet/versions/__init__.py +45 -0
  31. tonutils/contracts/wallet/versions/hw.py +215 -0
  32. tonutils/contracts/wallet/versions/pp.py +88 -0
  33. tonutils/contracts/wallet/versions/v1.py +92 -0
  34. tonutils/contracts/wallet/versions/v2.py +81 -0
  35. tonutils/contracts/wallet/versions/v3.py +80 -0
  36. tonutils/contracts/wallet/versions/v4.py +102 -0
  37. tonutils/contracts/wallet/versions/v5.py +236 -0
  38. tonutils/exceptions.py +74 -25
  39. tonutils/protocols/__init__.py +9 -0
  40. tonutils/protocols/client.py +41 -0
  41. tonutils/protocols/contract.py +99 -0
  42. tonutils/protocols/wallet.py +116 -0
  43. tonutils/tonconnect/__init__.py +0 -11
  44. tonutils/types/__init__.py +187 -0
  45. tonutils/types/client.py +7 -0
  46. tonutils/types/common.py +39 -0
  47. tonutils/types/configs.py +79 -0
  48. tonutils/types/contract.py +79 -0
  49. tonutils/types/keystructs.py +91 -0
  50. tonutils/types/messages.py +142 -0
  51. tonutils/types/opcodes.py +15 -0
  52. tonutils/types/params.py +85 -0
  53. tonutils/types/stack.py +17 -0
  54. tonutils/types/tlb/__init__.py +87 -0
  55. tonutils/types/tlb/content.py +156 -0
  56. tonutils/types/tlb/contract.py +9 -0
  57. tonutils/types/tlb/msg.py +36 -0
  58. tonutils/types/tlb/nft.py +626 -0
  59. tonutils/types/tlb/text.py +53 -0
  60. tonutils/types/tlb/wallet.py +299 -0
  61. tonutils/utils/__init__.py +51 -0
  62. tonutils/utils/converters.py +58 -0
  63. tonutils/utils/msg_builders.py +82 -0
  64. tonutils/utils/parse_config.py +35 -0
  65. tonutils/utils/stack_codec.py +188 -0
  66. tonutils/utils/text_cipher.py +140 -0
  67. tonutils/utils/validations.py +23 -0
  68. tonutils/utils/value_utils.py +62 -0
  69. tonutils/utils/wallet_utils.py +55 -0
  70. {tonutils-0.5.2.dist-info → tonutils-0.6.0a1.dist-info}/METADATA +5 -10
  71. tonutils-0.6.0a1.dist-info/RECORD +76 -0
  72. {tonutils-0.5.2.dist-info → tonutils-0.6.0a1.dist-info}/WHEEL +1 -1
  73. {tonutils-0.5.2.dist-info → tonutils-0.6.0a1.dist-info}/licenses/LICENSE +1 -1
  74. tonutils/account.py +0 -32
  75. tonutils/cache.py +0 -82
  76. tonutils/client/_base.py +0 -292
  77. tonutils/client/lite.py +0 -163
  78. tonutils/client/quicknode.py +0 -33
  79. tonutils/client/tatum.py +0 -50
  80. tonutils/client/tonapi.py +0 -145
  81. tonutils/client/toncenter.py +0 -303
  82. tonutils/client/utils.py +0 -203
  83. tonutils/contract.py +0 -184
  84. tonutils/dns/__init__.py +0 -5
  85. tonutils/dns/categories.py +0 -15
  86. tonutils/dns/contract.py +0 -256
  87. tonutils/dns/op_codes.py +0 -1
  88. tonutils/dns/subdomain_collection/__init__.py +0 -5
  89. tonutils/dns/subdomain_collection/content.py +0 -18
  90. tonutils/dns/subdomain_collection/contract.py +0 -91
  91. tonutils/dns/subdomain_collection/data.py +0 -63
  92. tonutils/dns/subdomain_collection/op_codes.py +0 -5
  93. tonutils/dns/subdomain_manager/__init__.py +0 -5
  94. tonutils/dns/subdomain_manager/contract.py +0 -210
  95. tonutils/dns/subdomain_manager/data.py +0 -38
  96. tonutils/dns/subdomain_manager/op_codes.py +0 -1
  97. tonutils/dns/utils.py +0 -115
  98. tonutils/jetton/__init__.py +0 -15
  99. tonutils/jetton/content.py +0 -79
  100. tonutils/jetton/contract/__init__.py +0 -10
  101. tonutils/jetton/contract/base/__init__.py +0 -5
  102. tonutils/jetton/contract/base/master.py +0 -76
  103. tonutils/jetton/contract/stablecoin/__init__.py +0 -9
  104. tonutils/jetton/contract/stablecoin/master.py +0 -215
  105. tonutils/jetton/contract/stablecoin/op_codes.py +0 -17
  106. tonutils/jetton/contract/stablecoin/wallet.py +0 -134
  107. tonutils/jetton/contract/standard/__init__.py +0 -7
  108. tonutils/jetton/contract/standard/master.py +0 -141
  109. tonutils/jetton/contract/standard/op_codes.py +0 -11
  110. tonutils/jetton/contract/standard/wallet.py +0 -132
  111. tonutils/jetton/data.py +0 -165
  112. tonutils/jetton/dex/__init__.py +0 -0
  113. tonutils/jetton/dex/dedust/__init__.py +0 -5
  114. tonutils/jetton/dex/dedust/constants.py +0 -48
  115. tonutils/jetton/dex/dedust/factory.py +0 -362
  116. tonutils/jetton/dex/stonfi/__init__.py +0 -10
  117. tonutils/jetton/dex/stonfi/utils.py +0 -47
  118. tonutils/jetton/dex/stonfi/v1/__init__.py +0 -7
  119. tonutils/jetton/dex/stonfi/v1/pton/__init__.py +0 -5
  120. tonutils/jetton/dex/stonfi/v1/pton/constants.py +0 -19
  121. tonutils/jetton/dex/stonfi/v1/pton/pton.py +0 -78
  122. tonutils/jetton/dex/stonfi/v1/router/__init__.py +0 -5
  123. tonutils/jetton/dex/stonfi/v1/router/constants.py +0 -38
  124. tonutils/jetton/dex/stonfi/v1/router/router.py +0 -193
  125. tonutils/jetton/dex/stonfi/v2/__init__.py +0 -7
  126. tonutils/jetton/dex/stonfi/v2/pton/__init__.py +0 -5
  127. tonutils/jetton/dex/stonfi/v2/pton/constants.py +0 -21
  128. tonutils/jetton/dex/stonfi/v2/pton/pton.py +0 -102
  129. tonutils/jetton/dex/stonfi/v2/router/__init__.py +0 -5
  130. tonutils/jetton/dex/stonfi/v2/router/constants.py +0 -41
  131. tonutils/jetton/dex/stonfi/v2/router/router.py +0 -308
  132. tonutils/nft/__init__.py +0 -22
  133. tonutils/nft/content.py +0 -135
  134. tonutils/nft/contract/__init__.py +0 -0
  135. tonutils/nft/contract/base/__init__.py +0 -7
  136. tonutils/nft/contract/base/collection.py +0 -80
  137. tonutils/nft/contract/base/nft.py +0 -71
  138. tonutils/nft/contract/editable/__init__.py +0 -9
  139. tonutils/nft/contract/editable/collection.py +0 -341
  140. tonutils/nft/contract/editable/nft.py +0 -155
  141. tonutils/nft/contract/soulbound/__init__.py +0 -9
  142. tonutils/nft/contract/soulbound/collection.py +0 -277
  143. tonutils/nft/contract/soulbound/nft.py +0 -123
  144. tonutils/nft/contract/standard/__init__.py +0 -9
  145. tonutils/nft/contract/standard/collection.py +0 -257
  146. tonutils/nft/contract/standard/nft.py +0 -78
  147. tonutils/nft/data.py +0 -95
  148. tonutils/nft/marketplace/__init__.py +0 -0
  149. tonutils/nft/marketplace/getgems/__init__.py +0 -5
  150. tonutils/nft/marketplace/getgems/addresses.py +0 -8
  151. tonutils/nft/marketplace/getgems/contract/__init__.py +0 -5
  152. tonutils/nft/marketplace/getgems/contract/salev3r3.py +0 -161
  153. tonutils/nft/marketplace/getgems/data.py +0 -54
  154. tonutils/nft/marketplace/getgems/op_codes.py +0 -7
  155. tonutils/nft/op_codes.py +0 -19
  156. tonutils/nft/royalty_params.py +0 -29
  157. tonutils/tonconnect/connector.py +0 -699
  158. tonutils/tonconnect/models/__init__.py +0 -53
  159. tonutils/tonconnect/models/account.py +0 -57
  160. tonutils/tonconnect/models/chain.py +0 -10
  161. tonutils/tonconnect/models/device.py +0 -137
  162. tonutils/tonconnect/models/event.py +0 -33
  163. tonutils/tonconnect/models/proof.py +0 -80
  164. tonutils/tonconnect/models/request.py +0 -533
  165. tonutils/tonconnect/models/wallet.py +0 -248
  166. tonutils/tonconnect/provider/__init__.py +0 -5
  167. tonutils/tonconnect/provider/bridge.py +0 -581
  168. tonutils/tonconnect/provider/session.py +0 -104
  169. tonutils/tonconnect/storage/__init__.py +0 -7
  170. tonutils/tonconnect/storage/base.py +0 -39
  171. tonutils/tonconnect/storage/default.py +0 -40
  172. tonutils/tonconnect/tonconnect.py +0 -290
  173. tonutils/tonconnect/utils/__init__.py +0 -25
  174. tonutils/tonconnect/utils/exceptions.py +0 -140
  175. tonutils/tonconnect/utils/logger.py +0 -3
  176. tonutils/tonconnect/utils/verifiers.py +0 -255
  177. tonutils/tonconnect/utils/wallet_manager.py +0 -239
  178. tonutils/utils.py +0 -267
  179. tonutils/vanity/__init__.py +0 -5
  180. tonutils/vanity/contract.py +0 -35
  181. tonutils/vanity/data.py +0 -34
  182. tonutils/wallet/__init__.py +0 -31
  183. tonutils/wallet/contract/__init__.py +0 -24
  184. tonutils/wallet/contract/_base.py +0 -438
  185. tonutils/wallet/contract/highload.py +0 -505
  186. tonutils/wallet/contract/preprocessed.py +0 -291
  187. tonutils/wallet/contract/v2.py +0 -95
  188. tonutils/wallet/contract/v3.py +0 -94
  189. tonutils/wallet/contract/v4.py +0 -122
  190. tonutils/wallet/contract/v5.py +0 -193
  191. tonutils/wallet/data.py +0 -188
  192. tonutils/wallet/messages.py +0 -631
  193. tonutils/wallet/op_codes.py +0 -9
  194. tonutils/wallet/utils.py +0 -57
  195. tonutils-0.5.2.dist-info/RECORD +0 -131
  196. {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
+ )