Skip to content

Commit

Permalink
refactor: rework cell parsing + add more type hints
Browse files Browse the repository at this point in the history
  • Loading branch information
gtors committed May 11, 2024
1 parent 5557a62 commit 3226c68
Show file tree
Hide file tree
Showing 27 changed files with 395 additions and 328 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ print(
```python
from tonsdk_ng.contract.token.ft import JettonWallet
from tonsdk_ng.contract.token.nft import NFTItem
from tonsdk_ng.utils import Address, to_nano
from tonsdk_ng.types import Address
from tonsdk_ng.utils import to_nano

body = NFTItem().create_transfer_body(Address("New Owner Address"))
body = NFTItem().create_transfer_body(Address.from_string("New Owner Address"))
query = wallet.create_transfer_message(
"NFT Item Address",
to_nano(0.05, "ton"),
Expand All @@ -70,7 +71,7 @@ query = wallet.create_transfer_message(
nft_boc = bytes_to_b64str(query["message"].to_boc(False))

body = JettonWallet().create_transfer_body(
Address("Destination address"), to_nano(40000, "ton") # jettons amount
Address.from_string("Destination address"), to_nano(40000, "ton") # jettons amount
)
query = wallet.create_transfer_message(
"Jetton Wallet Address",
Expand Down Expand Up @@ -100,7 +101,7 @@ from abc import ABC, abstractmethod
import aiohttp
from tvm_valuetypes import serialize_tvm_stack

from tonsdk_ng.boc import Cell
from tonsdk_ng.types import Cell
from tonsdk_ng.provider import (
SyncTonlibClient,
ToncenterClient,
Expand Down
7 changes: 4 additions & 3 deletions examples/tokens/jetton/transfer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from tonsdk_ng.contract.token.ft import JettonWallet
from tonsdk_ng.contract.wallet import Wallets, WalletVersionEnum
from tonsdk_ng.utils import Address, bytes_to_b64str, to_nano
from tonsdk_ng.types import Address
from tonsdk_ng.utils import bytes_to_b64str, to_nano

"""your wallet mnemonics"""
mnemonics = [
Expand Down Expand Up @@ -29,14 +30,14 @@
"piano",
"language",
]
mnemonics, pub_k, priv_k, wallet = Wallets.from_mnemonics(
wallet = Wallets.from_mnemonics(
mnemonics=mnemonics, version=WalletVersionEnum.v3r2, workchain=0
)


"""transfer"""
body = JettonWallet().create_transfer_body(
to_address=Address("address"),
to_address=Address.from_string("address"),
jetton_amount=to_nano(float("jettons amount"), "ton"),
)

Expand Down
7 changes: 4 additions & 3 deletions examples/tokens/nft/transfer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from tonsdk_ng.contract.token.nft import NFTItem
from tonsdk_ng.contract.wallet import Wallets, WalletVersionEnum
from tonsdk_ng.utils import Address, bytes_to_b64str, to_nano
from tonsdk_ng.types import Address
from tonsdk_ng.utils import bytes_to_b64str, to_nano

"""your wallet mnemonics"""
mnemonics = [
Expand Down Expand Up @@ -29,14 +30,14 @@
"piano",
"language",
]
mnemonics, pub_k, priv_k, wallet = Wallets.from_mnemonics(
wallet = Wallets.from_mnemonics(
mnemonics=mnemonics, version=WalletVersionEnum.v3r2, workchain=0
)


"""transfer"""
body = NFTItem().create_transfer_body(
new_owner_address=Address("new owner address")
new_owner_address=Address.from_string("new owner address")
)
query = wallet.create_transfer_message(
to_addr="nft addr",
Expand Down
6 changes: 4 additions & 2 deletions examples/types/cell.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from tonsdk_ng.boc import begin_cell
from tonsdk_ng.utils import Address
from tonsdk_ng.types import Address

cell = (
begin_cell()
.store_uint(4, 32)
.store_address(Address("EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG"))
.store_address(
Address.from_string("EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG")
)
.end_cell()
)
7 changes: 4 additions & 3 deletions examples/types/slice.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from tonsdk_ng.boc import begin_cell
from tonsdk_ng.utils import Address
from tonsdk_ng.types import Address, begin_cell

cell = (
begin_cell()
.store_uint(4, 32)
.store_address(Address("EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG"))
.store_address(
Address.from_string("EQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XggGG")
)
.end_cell()
)

Expand Down
114 changes: 79 additions & 35 deletions tonsdk_ng/contract/__init__.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,59 @@
import abc
from typing import Any, TypedDict, cast

from ..boc import Cell
from ..utils import Address
from ..types import Address, Cell


class StateInit(TypedDict):
code: Cell
data: Cell
address: Address
state_init: Cell | None


class Options(TypedDict):
wc: int
code: Cell
address: Address
public_key: bytes
private_key: bytes


class ExternalMessage(TypedDict):
address: Address
message: Cell
state_init: Cell | None
code: Cell | None
data: Cell | None


class Contract(abc.ABC):
def __init__(self, **kwargs):
self.options = kwargs
def __init__(self, **kwargs: Any):
self.options = cast(Options, kwargs)
self._address = (
Address(kwargs["address"]) if "address" in kwargs else None
Address.from_any(kwargs["address"]) if "address" in kwargs else None
)
if "wc" not in kwargs:
kwargs["wc"] = self._address.wc if self._address is not None else 0
self.options["wc"] = (
self._address.wc if self._address is not None else 0
)

@property
def address(self):
def address(self) -> Address:
if self._address is None:
self._address = self.create_state_init()["address"]

return self._address

def create_state_init(self):
def create_state_init(self) -> StateInit:
code_cell = self.create_code_cell()
data_cell = self.create_data_cell()
state_init = self.__create_state_init(code_cell, data_cell)
state_init_hash = state_init.bytes_hash()

address = Address(str(self.options["wc"]) + ":" + state_init_hash.hex())
address = Address.from_string(
str(self.options["wc"]) + ":" + state_init_hash.hex()
)

return {
"code": code_cell,
Expand All @@ -35,15 +62,15 @@ def create_state_init(self):
"state_init": state_init,
}

def create_code_cell(self):
def create_code_cell(self) -> Cell:
if "code" not in self.options or self.options["code"] is None:
raise Exception("Contract: options.code is not defined")
return self.options["code"]

def create_data_cell(self):
def create_data_cell(self) -> Cell:
return Cell()

def create_init_external_message(self):
def create_init_external_message(self) -> ExternalMessage:
create_state_init = self.create_state_init()
state_init = create_state_init["state_init"]
address = create_state_init["address"]
Expand All @@ -60,42 +87,48 @@ def create_init_external_message(self):
}

@classmethod
def create_external_message_header(cls, dest, src=None, import_fee=0):
def create_external_message_header(
cls,
dest: str | Address,
src: str | Address | None = None,
import_fee: int = 0,
) -> Cell:
message = Cell()
message.bits.write_uint(2, 2)
message.bits.write_address(Address(src) if src else None)
message.bits.write_address(Address(dest))
message.bits.write_address(Address.from_any(src) if src else None)
message.bits.write_address(Address.from_any(dest))
message.bits.write_grams(import_fee)
return message

@classmethod
def create_internal_message_header(
cls,
dest,
grams=0,
ihr_disabled=True,
bounce=None,
bounced=False,
src=None,
currency_collection=None,
ihr_fees=0,
fwd_fees=0,
created_lt=0,
created_at=0,
):
dest: str | Address,
grams: int = 0,
ihr_disabled: bool = True,
bounce: bool | None = None,
bounced: bool = False,
src: str | Address | None = None,
currency_collection: Any | None = None,
ihr_fees: int = 0,
fwd_fees: int = 0,
created_lt: int = 0,
created_at: int = 0,
) -> Cell:
message = Cell()
message.bits.write_bit(0)
message.bits.write_bit(ihr_disabled)

if bounce is not None:
message.bits.write_bit(bounce)
else:
message.bits.write_bit(Address(dest).is_bounceable)
message.bits.write_bit(Address.from_any(dest).is_bounceable)
message.bits.write_bit(bounced)
message.bits.write_address(Address(src) if src else None)
message.bits.write_address(Address(dest))
message.bits.write_address(Address.from_any(src) if src else None)
message.bits.write_address(Address.from_any(dest))
message.bits.write_grams(grams)
if currency_collection:
# TODO: implement currency collections
raise Exception("Currency collections are not implemented yet")

message.bits.write_bit(bool(currency_collection))
Expand All @@ -111,8 +144,8 @@ def create_out_msg(
address: str,
amount: int,
payload: str | bytes | Cell | None = None,
state_init=None,
):
state_init: Cell | None = None,
) -> Cell:
payload_cell = Cell()
if payload:
if isinstance(payload, Cell):
Expand All @@ -131,7 +164,12 @@ def create_out_msg(
return order

@classmethod
def create_common_msg_info(cls, header, state_init=None, body=None):
def create_common_msg_info(
cls,
header: Cell,
state_init: Cell | None = None,
body: Cell | None = None,
) -> Cell:
common_msg_info = Cell()
common_msg_info.write_cell(header)
if state_init:
Expand Down Expand Up @@ -164,9 +202,15 @@ def create_common_msg_info(cls, header, state_init=None, body=None):
return common_msg_info

def __create_state_init(
self, code, data, library=None, split_depth=None, ticktock=None
):
self,
code: Cell,
data: Cell,
library: Cell | None = None,
split_depth: Cell | None = None,
ticktock: Cell | None = None,
) -> Cell:
if library or split_depth or ticktock:
# TODO: implement library/split_depth/ticktock
raise Exception(
"Library/SplitDepth/Ticktock in state init is not implemented"
)
Expand Down
11 changes: 6 additions & 5 deletions tonsdk_ng/contract/wallet/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from enum import Enum
from typing import Any

from ...crypto import (
mnemonic_from_password,
Expand Down Expand Up @@ -35,7 +36,7 @@ class WalletVersionEnum(str, Enum):

class Wallets:
default_version = WalletVersionEnum.v4r2
ALL = {
ALL: dict[WalletVersionEnum, type[WalletContract]] = {
WalletVersionEnum.v2r1: WalletV2ContractR1,
WalletVersionEnum.v2r2: WalletV2ContractR2,
WalletVersionEnum.v3r1: WalletV3ContractR1,
Expand All @@ -52,7 +53,7 @@ def create(
version: WalletVersionEnum,
workchain: int,
password: str | None = None,
**kwargs,
**kwargs: Any,
) -> tuple[list[str], bytes, bytes, WalletContract]:
mnemonics = (
mnemonic_from_password(password) if password else mnemonic_new()
Expand All @@ -70,7 +71,7 @@ def from_mnemonics(
mnemonics: list[str],
version: WalletVersionEnum = default_version,
workchain: int = 0,
**kwargs,
**kwargs: Any,
) -> WalletContract:
if not mnemonic_is_valid(mnemonics):
raise InvalidMnemonicsError()
Expand All @@ -86,7 +87,7 @@ def from_private_key(
private_key: bytes,
version: WalletVersionEnum = default_version,
workchain: int = 0,
**kwargs,
**kwargs: Any,
) -> WalletContract:
public_key = private_key_to_public_key(private_key)
return cls.ALL[version](
Expand All @@ -102,7 +103,7 @@ def to_addr_pk(
mnemonics: list[str],
version: WalletVersionEnum = default_version,
workchain: int = 0,
**kwargs,
**kwargs: Any,
) -> tuple[bytes, bytes]:
wallet = cls.from_mnemonics(mnemonics, version, workchain, **kwargs)
pub_k, priv_k = mnemonic_to_wallet_key(mnemonics)
Expand Down
Loading

0 comments on commit 3226c68

Please sign in to comment.