Skip to main content
This section provides a complete guide to managing wallets using the tonutils library. It covers key operations such as:
  • Creating and deploying wallets
  • Importing wallets from mnemonic or private key
  • Reading on-chain wallet information
  • Sending transactions (TON, NFTs, jettons)
  • Performing batch and sequential transfers
  • Sending gasless (relayed) jetton transfers
  • Rotating the mnemonic of a Telegram Wallet
  • Encrypting and decrypting on-chain messages

Supported Wallets

The library supports multiple wallet versions and types, all importable from tonutils.contracts:

Create Wallet

To create a new wallet, use the .create() classmethod of the wallet class you select. It returns a 4-tuple: the wallet instance, its public key, private key, and a freshly generated mnemonic phrase. Each wallet class takes an optional config= argument (WalletV4Config, WalletV5Config, etc. from ton_core), where you can customize subwallet_id to derive multiple wallets from the same mnemonic. By default .create() generates a 24-word TON mnemonic. Without mnemonic_type, mnemonic_length=12 gives a Multichain (BIP-39) mnemonic and a longer one a TON mnemonic; pass mnemonic_type to choose the scheme explicitly, for example a 24-word Multichain mnemonic. WalletTg always generates a 12-word Multichain mnemonic, the format used by Telegram Wallet.
To use a different wallet version, swap the class and its config together: for example WalletV5R1 with WalletV5Config, or WalletHighloadV3R1 with WalletHighloadV3Config. Configs are imported from ton_core.

Import Wallet

You can import a wallet either from a mnemonic phrase or directly from a private key. from_mnemonic() returns the same 4-tuple as .create(); from_private_key() returns only the wallet instance.

From Mnemonic

Both mnemonic schemes are supported: TON mnemonics and Multichain (BIP-39) mnemonics. The scheme is detected by checksum, and a phrase valid in both schemes uses the wallet default; to set it explicitly, pass mnemonic_type=MnemonicType.TON or mnemonic_type=MnemonicType.MULTICHAIN. WalletTg uses the rotation mnemonic format: 12 words, or 24 after a key rotation; see Telegram Wallet.

From Private Key

PrivateKey from ton_core accepts the key in multiple formats: raw bytes, a hex string, a base64 string, or an integer.

Deploy Wallet

Wallets deploy automatically on their first outgoing transaction. To deploy explicitly, reconstruct the wallet from a mnemonic and send a small amount to its own address — after the transaction, the wallet transitions from uninit to active status.
wallet.transfer(...) returns an ExternalMessage. Its normalized_hash is computed locally before sending — it is not the on-chain transaction hash. Use it to track whether the message was accepted on-chain via explorers or API queries.

Wallet Information

To inspect a wallet without signing anything, initialize it from an address with .from_address() (read-only mode). Call await wallet.refresh() to fetch the latest on-chain state before reading properties.
If you also need to send transactions, initialize the wallet from a mnemonic instead — .refresh() and the state properties work the same way. For arbitrary contracts, see Get Contract Information.

Transfers

Send TON

Use wallet.transfer() to send TON with an optional text comment. The recipient can be an address or a .ton / .t.me domain; a domain resolves to its wallet record and is sent non-bounceable. The same applies to destination of TONTransferBuilder, JettonTransferBuilder and NFTTransferBuilder.
Parameters:
  • destination — recipient address (Address).
  • amount — amount in nanotons; use to_nano() to convert from TON (int).
  • body — optional text comment, visible in explorers and the recipient wallet (str or Cell).

Send NFT

NFT transfers use NFTTransferBuilder with wallet.transfer_message(). The sending wallet must be the current owner of the NFT.
Parameters:
  • destination — new owner address (Address).
  • nft_address — NFT item contract address (Address).
  • forward_payload — optional message forwarded to the new owner, visible in the notification (str or Cell).
  • forward_amount — nanotons sent to the new owner with the ownership_assigned notification (TEP-62); must be greater than 0 to trigger the notification (int).
  • amount — TON attached to the NFT item for gas fees; 0.05 TON is typically sufficient, increase it if forward_amount is higher (int).

Send Jetton

Jetton transfers use JettonTransferBuilder with wallet.transfer_message(). The wallet must hold a jetton balance in its jetton wallet.
Parameters:
  • destination — recipient address that receives the jettons (Address).
  • jetton_amount — amount in base units, respecting the token’s decimals (int).
  • jetton_master_address — jetton master contract address identifying the token (Address).
  • forward_payload — optional message forwarded to the recipient, visible in the notification (str or Cell).
  • forward_amount — nanotons sent to the recipient with the transfer_notification (TEP-74); must be greater than 0 to trigger the notification (int).
  • amount — TON attached to the jetton wallet for gas fees; 0.05 TON is typically sufficient (int).
Jetton amounts respect the token’s decimals, which are not always 9. For USDT-like jettons with 6 decimals, convert with to_nano(1, decimals=6).

Batch Transfers

Send multiple transfers in a single transaction by passing a list of builders to wallet.batch_transfer_message(). You can mix TONTransferBuilder, NFTTransferBuilder, and JettonTransferBuilder in one batch.
Message limits per wallet version are listed in Supported Wallets; exceeding the limit raises an error.

Sequential Transfers

Standard wallets reject a transaction whose seqno has already been used. If you send several transfers in quick succession, the second one can reuse the same on-chain seqno and fail. Wrap the wallet in SeqnoGuard to send safely in sequence — it waits for the on-chain seqno to advance after each send before allowing the next.

Gasless Transfers

Gasless transfers let a wallet send jettons without holding TON for gas: a relay pays the TON fees, and its commission is deducted from the sender’s jetton balance. The flow is two steps — gasless_estimate() to build and price the transfer, then gasless_send() to sign and relay it. Gasless transfers require TonapiClient on mainnet and are only available for WalletV5 (WalletV5R1 and WalletV5Beta).
A Tonapi API key is required — get one at tonconsole.com. Always review estimate.commission, estimate.valid_until, and the emulation result before calling gasless_send(); once sent, the transaction is irreversible.
The same flow is also available as a standalone recipe: Send Gasless Transaction.

Telegram Wallet

WalletTg is the wallet contract used by Telegram. Its account code is a small immutable trampoline that runs shared logic stored in the blockchain config, so every WalletTg uses the same latest contract version, updated by validator voting. It supports up to 255 messages per transaction and adds one capability the standard wallets do not have: rotating its signing key on-chain. Its default subwallet_id is network-specific and resolved automatically from the client’s network. A Telegram Wallet mnemonic has 12 words, or 24 after a key rotation. Words 1–12 derive the address and never change; words 13–24 hold the current signing key. Each half is a separate 12-word Multichain (BIP-39) mnemonic. from_mnemonic() accepts both forms; TON mnemonics are not supported, open such a wallet with from_private_key(). With only the private key of a rotated wallet, open it by address: WalletTg(client, address, private_key=key).

Rotate Mnemonic

rotate_mnemonic() replaces the wallet’s on-chain signing key with the key from words 13–24 of a new mnemonic. The wallet address does not change: the balance and history stay in place.
Store the new mnemonic before the call: it is the only copy of the new key. Once the rotation is accepted, the old mnemonic no longer controls the wallet.

Encrypted Messages

The library supports end-to-end encrypted comments using elliptic curve Diffie-Hellman (ECDH): only the sender and the recipient can decrypt the message.

Encrypt

Pass encrypt=True to transfer() (or to TONTransferBuilder in a batch) to send the text comment encrypted; JettonTransferBuilder and NFTTransferBuilder take the same flag for a text forward_payload. The recipient’s public key is fetched from its wallet via the get_public_key get-method; for an undeployed recipient, pass it as recipient_public_key.
Parameters:
  • encrypt — encrypt the text body for the recipient (bool).
  • recipient_public_key — recipient’s public key, or None to fetch it (PublicKey | None).

Decrypt

Decrypt an incoming encrypted comment with TextCipher.decrypt(). The sender’s public key is recovered from the encrypted payload (it is stored XORed with the recipient’s public key), so only the sender’s address and the recipient’s private key are needed.
Parameters:
  • payload — encrypted message as bytes, hex string, base64 string (cipher text only), or a Cell containing the opcode 0x2167DA4B and cipher text.
  • sender_address — original sender’s address, used for verification (Address).
  • our_private_key — recipient’s private key for ECDH decryption (PrivateKey).
For more details, see Send Encrypted Message.

Wallet Examples

Full runnable wallet example scripts on GitHub.