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
  • 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.
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

Mnemonics can be 24 words (TON-native) or 12/18/24 words (BIP-39 import).

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.
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.

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

Fetch the recipient’s public key with get_public_key_get_method(), encrypt the text with TextCipher.encrypt(), and send the resulting body with a regular transfer. The recipient’s wallet must be deployed (active state) and expose the get_public_key get-method.
Parameters:
  • payload — plaintext message to encrypt (str).
  • sender_address — sender’s address, used as a salt for message-key derivation and verification; the recipient must pass the same address to decrypt (Address).
  • our_private_key — sender’s private key for ECDH (PrivateKey).
  • their_public_key — recipient’s public key for ECDH (PublicKey).

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.