{"id":33898647,"url":"https://github.com/ton-blockchain/ton4j","last_synced_at":"2026-04-02T11:56:37.835Z","repository":{"id":61367435,"uuid":"543738405","full_name":"ton-blockchain/ton4j","owner":"ton-blockchain","description":"Java libraries for interacting with TON blockchain.","archived":false,"fork":false,"pushed_at":"2026-03-24T07:21:26.000Z","size":145476,"stargazers_count":124,"open_issues_count":17,"forks_count":43,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-25T09:02:07.199Z","etag":null,"topics":["blockchain","fift","func","java","mylocalton","telegram","ton","tonlib","tonlibjson"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ton-blockchain.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2022-09-30T18:32:41.000Z","updated_at":"2026-03-24T07:19:57.000Z","dependencies_parsed_at":"2024-11-11T11:27:52.067Z","dependency_job_id":"866388b5-4f96-49a4-a612-0da3706bbc20","html_url":"https://github.com/ton-blockchain/ton4j","commit_stats":null,"previous_names":["ton-blockchain/ton4j","neodix42/ton4j"],"tags_count":62,"template":false,"template_full_name":null,"purl":"pkg:github/ton-blockchain/ton4j","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ton-blockchain%2Fton4j","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ton-blockchain%2Fton4j/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ton-blockchain%2Fton4j/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ton-blockchain%2Fton4j/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ton-blockchain","download_url":"https://codeload.github.com/ton-blockchain/ton4j/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ton-blockchain%2Fton4j/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31305955,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T09:48:21.550Z","status":"ssl_error","status_checked_at":"2026-04-02T09:48:19.196Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","fift","func","java","mylocalton","telegram","ton","tonlib","tonlibjson"],"created_at":"2025-12-11T21:02:16.188Z","updated_at":"2026-04-02T11:56:37.828Z","avatar_url":"https://github.com/ton-blockchain.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Java SDK for The Open Network (TON)\n\n[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)\n[![Based on TON][ton-svg]][ton]\n![GitHub last commit](https://img.shields.io/github/last-commit/ton-blockchain/ton4j)\n![](https://tokei.rs/b1/github/ton-blockchain/ton4j?category=code)\n![](https://tokei.rs/b1/github/ton-blockchain/ton4j?category=files)\n\nJava libraries and wrapper for interacting with TON blockchain. ton4j requires minimum `Java 11`.\n\n## Maven [![Maven Central][maven-central-svg]][maven-central]\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003esmartcontract\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Jitpack [![JitPack][jitpack-svg]][jitpack]\n\n```xml\n\n\u003crepositories\u003e\n    \u003crepository\u003e\n        \u003cid\u003ejitpack.io\u003c/id\u003e\n        \u003curl\u003ehttps://jitpack.io\u003c/url\u003e\n    \u003c/repository\u003e\n\u003c/repositories\u003e\n```\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003eton4j\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Repository structure\n\nYou can use each submodule individually. Click the module below to get more details.\n\n* [Tonlib](tonlib/README.md) - use external Tonlib shared library to communicate with TON blockchain.\n* [Adnl](adnl/README.md) - Lite-client based on native ADNL protocol.\n* [SmartContract](smartcontract/README.md) - create and deploy custom and predefined smart-contracts.\n* [Cell](cell/README.md) - create, read and manipulate Bag of Cells.\n* [BitString](bitstring/README.md) - construct bit-strings.\n* [Address](address/README.md) - create and parse TON wallet addresses.\n* [Mnemonic](mnemonic/README.md) - helpful methods for generating deterministic keys for TON blockchain.\n* [Emulator](emulator/README.md) - wrapper for using with external precompiled emulator shared library.\n* [Exporter](exporter/README.md) - TON database reader/exporter that uses RocksDB Java JNA libraries.\n* [Liteclient](liteclient/README.md) - wrapper for using with external precompiled lite-client binary.\n* [TonCenter Client V2](toncenter/README.md) - wrapper used to send REST calls\n  towards [TonCenter API v2](https://toncenter.com/api/v2/) .\n* [TonCenter Client V3](toncenter-indexer-v3/README.md) - wrapper used to send REST calls\n  towards [TonCenter Indexer API v3](https://toncenter.com/api/v3/) .\n* [Fift](fift/README.md) - wrapper for using external precompiled fift binary.\n* [Func](func/README.md) - wrapper for using external precompiled func binary.\n* [Tolk](tolk/README.md) - wrapper for using external precompiled tolk binary.\n* [TonConnect](tonconnect/README.md) – implementation of a TON Connect standard.\n* [Disassembler](disassembler/README.md) - TON Smart Contract disassembler.\n* [TL-B](tlb/README.md) - TL-B structures and their de/serialization.\n* [TL](tl/README.md) - TL structures and their de/serialization. Used mainly for lite-server queries and responses as\n  well as for RockDB key/values.\n* [Utils](utils/README.md) - create private and public keys, convert data, etc.\n\n## How to use\n\n- [Connection](#connection)\n    - [Tonlib shared library](#tonlib)\n    - [ADNL lite-client](#adnl-lite-client)\n    - [Native lite-client](#native-lite-client)\n    - [TonCenter API V2](#toncenter-api-v2)\n    - [TonCenter API V3](#toncenter-api-v3)\n    - [Ton Provider](#ton-provider)\n- [Smart contract address](#smart-contract-address)\n- [Wallets](#Wallets)\n    - [Create](#create-wallet)\n    - [Transfer](#transfer-toncoins-in-testnet)\n    - [Deploy and transfer with externally signed](#deploy-and-transfer-toncoins-signed-externally)\n    - [Transfer to up to 4 recipients](#Transfer-to-up-to-4-recipients)\n    - [Transfer to up to 1000 recipients](#Transfer-to-up-to-1000-recipients)\n    - [Transfer to up to 1000 recipients using Secp256k1 and externally signed](#Transfer-to-up-to-1000-recipients-using-Secp256k1-and-externally-signed)\n    - [Send message to a contract](#send-a-message-to-a-contract)\n    - [Send message signed externally](#send-message-signed-externally)\n- [Accounts](#Accounts)\n    - [List transactions](#get-account-transactions)\n    - [List messages](#get-account-messages)\n    - [Get balance](#get-account-balance)\n    - [Get state](#get-account-state)\n- [Get block](#get-blockchain-block)\n- [Mnemonic](#Generate-mnemonic-and-keypair)\n- [NFT](#NFT)\n    - [Mint NFT collection](#Mint-NFT-collection)\n    - [Mint NFT item](#Mint-NFT-item)\n    - [Get NFT information](#Get-NFT-information)\n    - [Transfer NFT](#Transfer-NFT)\n    - [Change NFT collection owner](#Change-NFT-collection-owner)\n    - [Edit NFT collection content](#Edit-NFT-collection-content)\n    - [Create your own NFT marketplace](#Create-your-own-NFT-marketplace)\n    - [Sell NFT](#Sell-NFT)\n    - [Cancel NFT sale](#Cancel-NFT-sale)\n    - [Buy NFT](#Buy-NFT)\n- [Jettons](#Jettons)\n    - [Create USDT jetton wallet](#Create-USDT-jetton-wallet)\n    - [Transfer USDT to a single wallet](#Transfer-USDT-to-a-single-wallet)\n    - [Transfer USDT to multiple wallets](#Transfer-USDT-to-multiple-wallets)\n    - [Mint Jetton](#Mint-jetton)\n    - [Get Jetton information](#Get-jetton-information)\n    - [Edit minter jetton content](#Edit-minter-jetton-content)\n    - [Edit jetton admin address](#Edit-jetton-admin-address)\n    - [Transfer Jetton](#Transfer-jetton)\n    - [Burn Jettons](#Burn-jettons)\n- [DNS](#DNS)\n    - [Resolve](#Resolve-DNS-records)\n    - [Deploy own root DNS](#Deploy-own-root-DNS)\n- [Smart Contracts](#Smart-Contracts)\n    - [Retrieve contract's information](#Smart-Contracts)\n    - [Develop custom smart contract](#Develop-custom-smart-contract)\n- [BitString](#BitString)\n- [Cells](#Cells)\n    - [Create using CellBuilder](#Cell-Builder)\n    - [Parse using CellSlice](#Cell-Slice)\n    - [Hashmaps / Dicts](#Hashmaps)\n    - [TLB Loader/Serializer](#TLB-Serialize-Deserialize)\n- [Emulators](#Emulators)\n    - [TVM emulator](#tvm-emulator)\n    - [TX emulator](#Transaction-emulator)\n- [TON Connect](#ton-connect)\n- [Smart contract disassembler](#Smart-contract-disassembler)\n- [Notes](#notes)\n\n## Connection\n\nIn the TON ecosystem you can interact with a TON blockchain in four ways:\n\n- **Tonlib shared library** — connect to lite-server via tonlibjson.so/dll/dylib shared library;\n- **ADNL lite-client** — used to connect to lite-server using native Java ADNL protocol implementation; In the current\n  implementation it does not download proofs on start and thus is much faster than tonlibjson.\n- **Native lite-client** — a java wrapper for compiled lite-client executable. Handles and parses responses returned by\n  lite-client. Obsolete way of connecting to TON blockchain and should not be used.\n- **TonCenter API** — a java wrapper to interact with a [TonCenter HTTP API](https://toncenter.com/) service. For\n  production usage consider getting an API key.\n\n`TonProvider` interface is used to unite three most commonly used clients `Tonlib`, `AdnlLiteClient` and `TonCenter`.\nIt is preferable to use it in all smart contract builders. See below.\n\nTo quickly run the below snippets, add a `lomboc` dependency to your project:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.projectlombok\u003c/groupId\u003e\n    \u003cartifactId\u003elombok\u003c/artifactId\u003e\n    \u003cversion\u003e1.18.38\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nand then other dependencies for particular use cases, like one of the below:\n\n```java\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003etonlib\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### Tonlib\n\nConnect to the TON Mainnet with the latest tonlibjson downloaded from the TON Github release.\nYou can also specify an absolute path to your tonlibjson shared library.\n\n```java\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003etonlib\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```java\nTonlib tonlib =\n  Tonlib.builder()\n    .pathToTonlibSharedLib(Utils.getTonlibGithubUrl())\n    .testnet(false)\n    .build();\nBlockIdExt block = tonlib.getLast().getLast();\nlog.info(\"block {}\", block);\n```\n\nMore examples with Tonlibjson can be found in [tests](tonlib/src/test/java/org/ton/ton4j/tonlib/TestTonlibJson.java).\n\n### ADNL lite-client\n\nConnect to the TON **Mainnet** using an ADNL lite-client.\n\n```java\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003eadnl\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```java\nAdnlLiteClient client = AdnlLiteClient.builder().mainnet().build();\nMasterchainInfo info = client.getMasterchainInfo();\n```\n\nConnect to the TON **Testnet**\n\n```java\nAdnlLiteClient client = AdnlLiteClient.builder().testnet().build();\nMasterchainInfo info = client.getMasterchainInfo();\n```\n\nConnect to **MyLocalTon**\n\n```java\nAdnlLiteClient client = AdnlLiteClient.builder().myLocalTon().build();\nMasterchainInfo info = client.getMasterchainInfo();\n```\n\nMore examples with AdnlLiteClient can be found\nin [tests](adnl/src/test/java/org/ton/ton4j/adnl/AdnlLiteClientTest.java).\n\n### Native lite-client\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003eliteclient\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nDownload lite-client executable and run its methods and parse the results\n\n```java\nLiteClient liteClient =\nLiteClient.builder()\n  .testnet(false)\n  .pathToLiteClientBinary(Utils.getLiteClientGithubUrl())\n  .build();\nString last = liteClient.executeLast();\nlog.info(\"Last command stdOut: {}\", last);\nResultLastBlock lastParsed = LiteClientParser.parseLast(last);\nlog.info(\"Last command parsed: {}\", lastParsed);\n\nliteClient.executeRunMethod(\n            \"EQDCJVrezD71y-KPcTIG-YeKNj4naeiR7odpQgVA1uDsZqPC\",\n            \"(-1,8000000000000000,20301499):070D07EB64D36CCA2D8D20AA644489637059C150E2CD466247C25B4997FB8CD9:D7D7271D466D52D0A98771F9E8DCAA06E43FCE01C977AACD9DE9DAD9A9F9A424\",\n            \"seqno\", \"\");\n```\n\nDownload the latest block's dump and parse it\n\n```java\nLiteClient liteClient =\n  LiteClient.builder()\n    .testnet(false)\n    .pathToLiteClientBinary(Utils.getLiteClientGithubUrl())\n    .build();\nString stdoutLast = liteClient.executeLast();\nResultLastBlock blockIdLast = LiteClientParser.parseLast(stdoutLast);\nString stdoutDumpblock = liteClient.executeDumpblock(blockIdLast);\nBlock block = LiteClientParser.parseDumpblock(stdoutDumpblock, false, true);\nlog.info(block.toString());\n```\n\nMore examples on how to work with LiteClient wrapper can be found\nin [tests](liteclient/src/test/java/org/ton/ton4j/liteclient/LiteClientTest.java).\n\n### TonCenter API V2\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003etoncenter\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nRun get method on smart contract. Empty API KEY means the default public rate limit is applied.\n\n```java\nTonCenter client = TonCenter.builder().apiKey(\"\").network(Network.MAINNET).build();\ntry {\n  TonResponse\u003cRunGetMethodResponse\u003e response =  client.runGetMethod(\"UQBmzW4wYlFW0tiBgj5sP1CgSlLdYs-VpjPWM7oPYPYWQBqW\", \"seqno\", new ArrayList\u003c\u003e());\n  log.info(\"response {}\", response.getResult());\n  log.info(\"Get method 'seqno' executed successfully\");\n} finally {\n  client.close();\n}\n```\n\nGet seqno alternative way\n\n```java\nTonCenter client = TonCenter.builder().apiKey(\"\").network(Network.MAINNET).build();\ntry {\n  long seqno = client.getSeqno(tonWallet);      \n  log.info(\"Get method 'seqno' executed successfully, seqno {}\", seqno);\n} finally {\n  client.close();\n}\n```\n\nMore TonCenter V2 examples in [tests](toncenter/src/test/java/org/ton/ton4j/toncenter/TonCenterTest.java).\n\n### TonCenter API V3\n\nGet account states\n\n```java\nTonCenterV3 client =\n  TonCenterV3.builder()\n    .mainnet()\n    .connectTimeout(Duration.ofSeconds(15))\n    .readTimeout(Duration.ofSeconds(30))\n    .apiKey(\"\")\n    .build();\n\nList\u003cString\u003e addresses = Collections.singletonList(\"0:a44757069a7b04e393782b4a2d3e5e449f19d16a4986a9e25436e6b97e45a16a\");\nAccountStatesResponse response = client.getAccountStates(addresses, true);\nlog.info(\"Retrieved {} account states\", response.getAccounts().size());\n```\n\nGet top accounts by balance\n\n```java\nTonCenterV3 client =\n  TonCenterV3.builder()\n    .mainnet()\n    .connectTimeout(Duration.ofSeconds(15))\n    .readTimeout(Duration.ofSeconds(30))\n    .apiKey(\"\")\n    .build();\ntry {\n  List\u003cAccountBalance\u003e response = client.getTopAccountsByBalance(10, 0);\n  log.info(\"Retrieved {} top accounts\", response.size());\n  if (!response.isEmpty()) {\n    log.info(\"Top account balance: {}\", response.get(0).getBalance());\n  }\n  log.info(response.toString());\n} finally {\n  client.close();\n}\n```\n\nGet traces. If you get error `{\"error\":\"timeout: context deadline exceeded\"}`, then use your own TON Center API KEY.\n\n```java\nTonCenterV3 client =\n  TonCenterV3.builder()\n    .mainnet()\n    .connectTimeout(Duration.ofSeconds(60))\n    .readTimeout(Duration.ofSeconds(60))\n    .apiKey(\"\")\n    .build();\ntry {\n  TracesResponse response = client.getTraces(\"0:a44757069a7b04e393782b4a2d3e5e449f19d16a4986a9e25436e6b97e45a16a\", null,null, null, null, null, null, null, null, null, null, 10, 0, \"desc\");\n  log.info(\"Retrieved traces\");\n} finally {\n  client.close();\n}\n```\n\nMore TonCenter V3 examples\nin [tests](toncenter-indexer-v3/src/test/java/org/ton/ton4j/toncenterv3/TonCenterV3Test.java).\n\n### Ton Provider\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003esmartcontract\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nAll `ton4j` wallet and smart contract classes accept `TonProvider` interface, e.g.:\n\nTonCenter as a TON client provider\n\n```java\nTonCenter tonCenterClient = TonCenter.builder().apiKey(\"\").mainnet().build();\nWalletV3R1 contract = WalletV3R1.builder().keyPair(\"keyPair\").tonProvider(tonCenterClient).walletId(42).build();\n```\n\nAdnlLiteClient as a TON client provider\n\n```java\nAdnlLiteClient adnlLiteClient =  AdnlLiteClient.builder().mainnet().build();\nWalletV3R1 contract = WalletV3R1.builder().keyPair(\"keyPair\").tonProvider(adnlLiteClient).walletId(42).build();\n```\n\nTonlib as a TON client provider\n\n```java\nTonlib tonlib =\n  Tonlib.builder()\n    .testnet(true)\n    .pathToTonlibSharedLib(Utils.getTonlibGithubUrl())\n    .ignoreCache(false)\n    .build();\nWalletV3R1 contract = WalletV3R1.builder().tonProvider(tonlib).walletId(42).build();\n```\n\n#### Interface\n\nAll TON clients in `ton4j` implement at least the following methods; however, individually each TON client has many more\nmethods.\n\n```java\nBigInteger getBalance(Address address);\nlong getSeqno(Address address);\nBigInteger getPublicKey(Address address);\nlong getSubWalletId(Address address);\nboolean isDeployed(Address address);\nvoid waitForDeployment(Address address, int timeoutSeconds);\nvoid waitForBalanceChange(Address address, int timeoutSeconds);\nvoid printAccountMessages(Address account);\nvoid printAccountMessages(Address account, int historyLimit);\nvoid printAccountTransactions(Address account);\nvoid printAccountTransactions(Address account, int historyLimit);\nvoid printAccountTransactions(Address account, int historyLimit, boolean withMessages);\nTransaction sendExternalMessageWithConfirmation(Message externalMessage);\nSendResponse sendExternalMessage(Message externalMessage);\n```\n\n## Smart contract address\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003eaddress\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nIn TON smart contract address has various [formats](https://docs.ton.org/foundations/addresses/formats).\n\n```java\nTweetNaclFast.Signature.KeyPair keyPair = Utils.generateSignatureKeyPair();\nTonlib tonlib = Tonlib.builder().pathToTonlibSharedLib(Utils.getTonlibGithubUrl()).build();\nWalletV3R2 wallet = WalletV3R2.builder().tonProvider(tonlib).keyPair(keyPair).walletId(42).build();\n\nString raw = wallet.getAddress().toRaw();\nlog.info(\"rawAddress: {}\", raw);\n\nString bounceableTestnet = wallet.getAddress().toBounceableTestnet();\nString nonBounceableTestnet = wallet.getAddress().toNonBounceableTestnet();\nlog.info(\"bounceableTestnet: {}\", bounceableTestnet);\nlog.info(\"nonBounceableTestnet: {}\", nonBounceableTestnet);\n\nString bounceableMainnet = wallet.getAddress().toBounceable();\nString nonBounceableMainnet = wallet.getAddress().toNonBounceable();\nlog.info(\"bounceableMainnet: {}\", bounceableMainnet);\nlog.info(\"nonBounceableMainnet: {}\", nonBounceableMainnet);\n```\n\nParse and convert base64 address to raw format\n\n```java\nAddress address = Address.of(\"EQDKbjIcfM6ezt8KjKJJLshZJJSqX7XOA4ff-W72r5gqPrHF\");\nString rawAddress = address.toRaw();\n```\n\nMore examples in [tests](address/src/test/java/org/ton/ton4j/address/TestAddress.java).\n\n## Wallets\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003esmartcontract\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nIn TON there are [many types of wallets](https://docs.ton.org/standard/wallets/history), i.e., smart contracts.\nThe most popular ones are V3R2 and V4R2 and V5R1.\nSome of them are advanced versions of the previous ones, and some have specific purpose, like vesting and multisig.\n\n### Create wallet\n\nCreate a simple wallet V3R2 in the Mainnet\n\n```java\n// prepare \nTweetNaclFast.Signature.KeyPair keyPair = Utils.generateSignatureKeyPair();\nTonProvider adnlLiteClient = AdnlLiteClient.builder().mainnet().build();\nWalletV3R2 contract = WalletV3R2.builder().tonProvider(adnlLiteClient).keyPair(keyPair).walletId(42).build();\n\n// to deploy a wallet, you have to top it up with some toncoins first\nString nonBounceableAddress = contract.getAddress().toNonBounceable();\n\n// now send some toncoins to nonBounceableAddress, normally up to 0.1 toncoins is enough, then deploy the wallet\ncontract.deploy();\n```\n\n### Transfer toncoins in Testnet\n\n```java\n// generate keypair, create TonProvider and define wallet \nTweetNaclFast.Signature.KeyPair keyPair = Utils.generateSignatureKeyPair();\nTonProvider adnlLiteClient = AdnlLiteClient.builder().testnet().build();\nWalletV3R2 contract = WalletV3R2.builder().tonProvider(adnlLiteClient).keyPair(keyPair).walletId(42).build();\n\n// to deploy a wallet, you have to top it up with some toncoins first\nString nonBounceableAddress = contract.getAddress().toNonBounceable();\nlog.info(\"non-bounceable address: {}\", nonBounceableAddress);\n\n// in testnet you can use a helper method that uses Testnet Faucet to top up the address with test toncoins\nTestnetFaucet.topUpContract(adnlLiteClient, Address.of(nonBounceableAddress), Utils.toNano(1));\n\n// send deploy message\ncontract.deploy();\n\n// wait till wallet is deployed\ncontract.waitForDeployment();\n\n// check if wallet is deployed\nlog.info(\"deployed: {}\", contract.isDeployed());\n\n// send toncoins\nWalletV3Config config =\n  WalletV3Config.builder()\n    .walletId(42)\n    .seqno(contract.getSeqno())\n    .destination(Address.of(TestnetFaucet.BOUNCEABLE))\n    .amount(Utils.toNano(0.8))\n    .comment(\"testWalletV3R2-42\")\n    .build();\n\n// transfer coins from a new wallet (back to faucet)\ncontract.send(config);\n```\n\n### Deploy and transfer toncoins signed externally\n\n```java\nTonProvider adnlLiteClient = AdnlLiteClient.builder().testnet().build();\nTweetNaclFast.Signature.KeyPair keyPair = Utils.generateSignatureKeyPair();\nbyte[] publicKey = keyPair.getPublicKey();\n// we use only a public key to create a wallet,\nWalletV3R2 contract = WalletV3R2.builder().tonProvider(adnlLiteClient).publicKey(publicKey).walletId(42).build();\n\nBigInteger balance = TestnetFaucet.topUpContract(tonlib, contract.getAddress(), Utils.toNano(0.1));\nlog.info(\"walletId {} new wallet {} balance: {}\",\n        contract.getWalletId(),\n        contract.getName(),\n        Utils.formatNanoValue(balance));\n\n// deploy using an externally signed body\nCell deployBody = contract.createDeployMessage();\n\n// sign deploy body with a private key wherever you want\nbyte[] signedDeployBodyHash = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), deployBody.hash());\n\ncontract.deploy(signedDeployBodyHash);\ncontract.waitForDeployment();\n\n// send toncoins\nWalletV3Config config =\n  WalletV3Config.builder()\n    .walletId(42)\n    .seqno(contract.getSeqno())\n    .destination(Address.of(TestnetFaucet.BOUNCEABLE))\n    .amount(Utils.toNano(0.08))\n    .comment(\"testWalletV3R2-signed-externally\")\n    .build();\n\n// transfer coins from a new wallet (back to faucet) using an externally signed body\nCell transferBody = contract.createTransferBody(config);\n// sign the transfer body with a private key wherever you want\nbyte[] signedTransferBodyHash = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), transferBody.hash());\nSendResponse sendResponse = contract.send(config, signedTransferBodyHash);\nlog.info(\"sendResponse: {}\", sendResponse);\n```\n\n### Transfer to up to 4 recipients\n\nIn TON there are [several ways](smartcontract/README-WALLETS.md) how to transfer toncoins to multiple users.\n\nYou can use WalletV2R2 to send toncoins to up to four recipients\n\n```java\nTweetNaclFast.Signature.KeyPair keyPair = Utils.generateSignatureKeyPair();\n\nTonProvider tonProvider = AdnlLiteClient.builder().testnet().liteServerIndex(2).build();\nWalletV2R1 contract = WalletV2R1.builder().tonProvider(tonProvider).keyPair(keyPair).build();\n\nString nonBounceableAddress = contract.getAddress().toNonBounceable();\nString bounceableAddress = contract.getAddress().toBounceable();\n\nlog.info(\"non-bounceable address {}\", nonBounceableAddress);\nlog.info(\"    bounceable address {}\", bounceableAddress);\n\n// top up new wallet using test-faucet-wallet\nBigInteger balance = TestnetFaucet.topUpContract(tonProvider, Address.of(nonBounceableAddress), Utils.toNano(1));\nlog.info(\"new wallet {} balance: {}\", contract.getName(), Utils.formatNanoValue(balance));\n\ncontract.deploy();\n\ncontract.waitForDeployment();\n\nlog.info(\"sending to 4 destinations...\");\nWalletV2R1Config config = WalletV2R1Config.builder()\n  .seqno(contract.getSeqno())\n  .destination1(Address.of(\"EQA84DSUMyREa1Frp32wxFATnAVIXnWlYrbd3TFS1NLCbC-B\"))\n  .destination2(Address.of(\"EQCJZ3sJnes-o86xOa4LDDug6Lpz23RzyJ84CkTMIuVCCuan\"))\n  .destination3(Address.of(\"EQBjS7elE36MmEmE6-jbHQZNEEK0ObqRgaAxXWkx4pDGeefB\"))\n  .destination4(Address.of(\"EQAaGHUHfkpWFGs428ETmym4vbvRNxCA1o4sTkwqigKjgf-_\"))\n  .amount1(Utils.toNano(0.15))\n  .amount2(Utils.toNano(0.15))\n  .amount3(Utils.toNano(0.15))\n  .amount4(Utils.toNano(0.15))\n  .build();\n\ncontract.sendWithConfirmation(config);\n\nlog.info(\"new wallet {} balance: {}\", contract.getName(), Utils.formatNanoValue(contract.getBalance()));\n\nlog.info(\"seqno {}\", contract.getSeqno());\n```\n\nOr you can use WalletV3R2 and construct a body with up to 4 recipients yourself.\nRefer to [this](smartcontract/src/main/java/org/ton/ton4j/smartcontract/wallet/v2/WalletV2R2.java) example, method\n`createTransferBody`, that contract cell with 4 references.\n\n### Transfer to up to 1000 recipients\n\nTo send toncoins or custom payloads to more than 4 recipients, use Highload Wallet V3.\n\n```java\nTweetNaclFast.Signature.KeyPair keyPair = Utils.generateSignatureKeyPair();\nAdnlLiteClient adnlClient = AdnlLiteClient.builder().testnet().liteServerIndex(2).build();\nTonProvider tonProvider = adnlClient;\ntry {\n    HighloadWalletV3 contract = HighloadWalletV3.builder().tonProvider(tonProvider).keyPair(keyPair).walletId(42).build();\n    String nonBounceableAddress = contract.getAddress().toNonBounceable();\n\n    log.info(\"non-bounceable address {}\", nonBounceableAddress);\n    BigInteger balance =  TestnetFaucet.topUpContract(tonProvider, Address.of(nonBounceableAddress), Utils.toNano(2));\n\n    log.info(\"new wallet {} balance: {}\", contract.getName(), Utils.formatNanoValue(balance));\n\n    HighloadV3Config config =\n      HighloadV3Config.builder()\n        .walletId(42)\n        .queryId(HighloadQueryId.fromSeqno(0).getQueryId())\n        .build();\n\n    contract.deploy(config);\n    contract.waitForDeployment();\n\n    config = HighloadV3Config.builder()\n        .walletId(42)\n        .queryId(HighloadQueryId.fromSeqno(1).getQueryId())\n        .body(contract.createBulkTransfer(createDummyDestinations(1000), BigInteger.valueOf(HighloadQueryId.fromSeqno(1).getQueryId())))\n        .build();\n\n    contract.send(config);\n    log.info(\"sent to 1000 recipients\");\n} finally {\n   adnlClient.close();\n}\n```\n\nIn the example above we used method `createDummyDestinations()`, replace it with your logic defining recipients\n\n```java\n  public static List\u003cDestination\u003e createDummyDestinations(int count) {\n    List\u003cDestination\u003e result = new ArrayList\u003c\u003e();\n    for (int i = 0; i \u003c count; i++) {\n      String dstDummyAddress = Utils.generateRandomAddress(0);\n      result.add(\n        Destination.builder()\n          .bounce(false)\n          .address(dstDummyAddress)\n          .amount(Utils.toNano(0.001))\n          .build());\n    }\n    return result;\n  }\n```\n\n### Transfer to up to 1000 recipients using Secp256k1 and externally signed\n\n```java\nAdnlLiteClient adnlClient = AdnlLiteClient.builder().testnet().liteServerIndex(2).build();\nSecp256k1KeyPair keyPair = Utils.generateSecp256k1SignatureKeyPair();\nbyte[] pubKey = keyPair.getPublicKey();\n\nHighloadWalletV3S contract =\n  HighloadWalletV3S.builder()\n    .tonProvider(adnlClient)\n    .publicKey(pubKey) // no private key is used\n    .walletId(42)\n    .build();\n\nString nonBounceableAddress = contract.getAddress().toNonBounceable();\nlog.info(\"non-bounceable address {}\", nonBounceableAddress);\n\n// top up a new wallet using test-faucet-wallet\nBigInteger balance = TestnetFaucet.topUpContract(adnlClient, Address.of(nonBounceableAddress), Utils.toNano(3));\nlog.info(\"new wallet {} balance: {}\", contract.getName(), Utils.formatNanoValue(balance));\n\nHighloadV3Config config =\n  HighloadV3Config.builder()\n    .walletId(42)\n    .queryId(HighloadQueryId.fromSeqno(0).getQueryId())\n    .build();\n\nCell deployBody = contract.createDeployMessage(config);\n\n// sign deployBody without exposing the private key and come back with a signature\nbyte[] signedDeployBody = Utils.signDataSecp256k1(deployBody.hash(), keyPair.getPrivateKey(), pubKey).getSignature();\n\ncontract.deploy(config, signedDeployBody);\n\ncontract.waitForDeployment();\n\nint queryId = HighloadQueryId.fromSeqno(1).getQueryId();\nconfig = HighloadV3Config.builder()\n  .walletId(42)\n  .queryId(queryId)\n  .body(contract.createBulkTransfer(createDummyDestinations(1000), BigInteger.valueOf(HighloadQueryId.fromSeqno(1).getQueryId())))\n  .build();\n\nCell transferBody = contract.createTransferMessage(config);\n\n// sign the transferBody without exposing the private key and come back with a signature\nbyte[] signedTransferBody = Utils.signDataSecp256k1(transferBody.hash(), keyPair.getPrivateKey(), keyPair.getPublicKey()).getSignature();\n\nSendResponse sendResponse = contract.send(config, signedTransferBody);\nlog.info(\"sendResponse {}   \", sendResponse);\nlog.info(\"sent to 1000 recipients\");\n```\n\n### Send a message to a contract\n\nYou can also send a custom payload to a smart contract\n\n```java\n// prepare \nTweetNaclFast.Signature.KeyPair keyPair = Utils.generateSignatureKeyPair();\nAdnlLiteClient adnlLiteClient =  AdnlLiteClient.builder().testnet().build();\nWalletV3R2 contract =  WalletV3R2.builder().tonProvider(adnlLiteClient).keyPair(keyPair).walletId(42).build();\n\n// to deploy a wallet, you have to top it up with some toncoins first\nString nonBounceableAddress = contract.getAddress().toNonBounceable();\nlog.info(\"non-bounceable address: {}\", nonBounceableAddress);\n\n// in testnet you can use a helper method that uses Testnet Faucet to top up the address with test toncoins\nTestnetFaucet.topUpContract(adnlLiteClient, Address.of(nonBounceableAddress), Utils.toNano(1));\n\n// deploy the wallet\ncontract.deploy();\n\n// check if wallet is deployed\ncontract.isDeployed();\n\n//send toncoins\nWalletV3Config config =\n  WalletV3Config.builder()\n    .walletId(42)\n    .seqno(contract.getSeqno())\n    .destination(Address.of(\"destination-wallet-address\"))\n    .amount(Utils.toNano(0.8))\n    .body(CellBuilder.beginCell().storeUint(2, 2).endCell()) // custom payload\n    .build();\n\n// transfer toncoins from a new wallet (back to faucet)\ncontract.send(config);\n```\n\n### Send a message signed externally\n\nIn a critical infrastructure you store customers' private keys in a secure place, like HSM or cold storage.\nIn that case you sign data outside the main application and use already signed data within an application.\n\n```java\nTweetNaclFast.Signature.KeyPair keyPair = Utils.generateSignatureKeyPair();\nbyte[] publicKey = keyPair.getPublicKey();\nAdnlLiteClient adnlLiteClient = AdnlLiteClient.builder().testnet().liteServerIndex(5).build();\n\nWalletV3R2 wallet =\n  WalletV3R2.builder().tonProvider(adnlLiteClient).publicKey(publicKey).walletId(42).build();\n  log.info(\"pub key: {}\", Utils.bytesToHex(publicKey));\n  log.info(\"wallet address: {}\", wallet.getAddress().toBounceable());\n\nBigInteger balance = TestnetFaucet.topUpContract(adnlLiteClient, wallet.getAddress(), Utils.toNano(0.1));\nlog.info(\"walletId {} new wallet {} balance: {}\",\n  wallet.getWalletId(),\n  wallet.getName(),\n  Utils.formatNanoValue(balance));\n\n// deploy using an externally signed body\nCell deployBody = wallet.createDeployMessage();\n\nbyte[] signedDeployBodyHash = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), deployBody.hash());\n\nwallet.deploy(signedDeployBodyHash);\nlog.info(\"deploying wallet\");\n\nwallet.waitForDeployment();\nlog.info(\"deployed\");\n\n// send toncoins\nWalletV3Config config =\n  WalletV3Config.builder()\n    .walletId(42)\n    .seqno(wallet.getSeqno())\n    .destination(Address.of(TestnetFaucet.BOUNCEABLE))\n    .amount(Utils.toNano(0.08))\n    .comment(\"testWalletV3R2-signed-externally\")\n    .build();\n\n// transfer coins from a new wallet (back to faucet) using an externally signed body\nCell transferBody = wallet.createTransferBody(config);\nbyte[] signedTransferBodyHash = Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), transferBody.hash());\nSendResponse sendResponse = wallet.send(config, signedTransferBodyHash);\nlog.info(\"sendResponse: {}\", sendResponse);\n```\n\nMore examples on how to work with TON wallets in [tests](smartcontract/src/test/java/org/ton/ton4j/smartcontract).\n\n## Accounts\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003esmartcontract\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003eadnl\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003etonlib\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### Get account transactions\n\nWith the help of an ADNL lite-client limited by 10 transactions\n\n```java\nAdnlLiteClient adnlLiteClient = AdnlLiteClient.builder().mainnet().build();\nTransactionList transactionList = adnlLiteClient.getTransactions(Address.of(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\"), 0, null, 10);\nfor (Transaction tx : transactionList.getTransactionsParsed()) {\n  log.info(\"tx {}\", tx);\n}\n```\n\nor\n\n```java\nAdnlLiteClient adnlLiteClient = AdnlLiteClient.builder().mainnet().build();        \nadnlLiteClient.printAccountTransactions(Address.of(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\"));\n```\n\nor with messages\n\n```java\nAdnlLiteClient adnlLiteClient = AdnlLiteClient.builder().mainnet().build();        \nadnlLiteClient.printAccountTransactions(Address.of(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\"), true);\n```\n\nWith help of Tonlibjson shared library\n\n```java\nTonlib tonlib = Tonlib.builder().pathToTonlibSharedLib(Utils.getTonlibGithubUrl()).testnet(false).build();\ntonlib.printAccountTransactions(Address.of(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\"), 20, true);\n```\n\n### Get account messages\n\nWith help of Tonlibjson shared library\n\n```java\nTonlib tonlib = Tonlib.builder().pathToTonlibSharedLib(Utils.getTonlibGithubUrl()).testnet(false).build();\ntonlib.printAccountMessages(Address.of(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\"), 20);\n```\n\n### Get account balance\n\nWith help of Tonlibjson shared library\n\n```java\nTonlib tonlib = Tonlib.builder().pathToTonlibSharedLib(Utils.getTonlibGithubUrl()).testnet(false).build();\nlog.info(\"balance {}\", tonlib.getAccountBalance(Address.of(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\")));\n```\n\nWith help of ADNL lite-client\n\n```java\nAdnlLiteClient adnlLiteClient = AdnlLiteClient.builder().mainnet().build();\nlog.info(\"balance {}\", adnlLiteClient.getBalance(Address.of(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\")));\n```\n\n### Get account state\n\n- Using TonCenter V3 client\n\n```java\nTonCenterV3 client =\n  TonCenterV3.builder()\n    .mainnet()\n    .connectTimeout(Duration.ofSeconds(15))\n    .readTimeout(Duration.ofSeconds(30))\n    .apiKey(\"\")\n    .build(); \ntry {\n  List\u003cString\u003e addresses = Collections.singletonList(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\");\n  AccountStatesResponse response = client.getAccountStates(addresses, true);\n  log.info(\"Retrieved {} account states\", response.getAccounts().size());\n  log.info(response.toString());\n} finally {\n  client.close();\n}\n```\n\nUsing an ADNL lite-client\n\n```java\n  AdnlLiteClient adnlLiteClient = AdnlLiteClient.builder().mainnet().build();\n  MasterchainInfo info = adnlLiteClient.getMasterchainInfo();\n  AccountState accountState = adnlLiteClient.getAccountState(info.getLast(), Address.of(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\"));\n```\n\nMany more examples on how to use different types of wallets can be found\nin [tests](smartcontract/src/test/java/org/ton/ton4j/smartcontract).\n\n## Get blockchain block\n\nGet the most recent block using an ADNL lite-client, parsed as per TL-B schema\n\n```java\nAdnlLiteClient adnlLiteClient = AdnlLiteClient.builder().mainnet().build();\nMasterchainInfo masterchainInfo = adnlLiteClient.getMasterchainInfo();\nBlockData blockData = adnlLiteClient.getBlock(masterchainInfo.getLast());\nlog.info(\"Block  {}\", blockData.getBlock());\n```\n\n## Generate mnemonic and keypair\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003emnemonic\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```java\n// generate 24-word mnemonic\nString mnemonic = Mnemonic.generateString(24);\n// convert it to Pair\nPair keyPair = Mnemonic.toKeyPair(mnemonic);\n// use generated mnemonic as a key pair for TON smart contracts\n// 64-byte signature keypair (32 pub + 32 priv)\nTweetNaclFast.Signature.KeyPair sigKeyPair = TweetNaclFast.Signature.keyPair_fromSeed(keyPair.getSecretKey());\n\n// Quick random signature keypair (no mnemonic)\nTweetNaclFast.Signature.KeyPair quickKeyPair = Utils.generateSignatureKeyPair();\n```\n\n## NFT\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003esmartcontract\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003eadnl\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003eutils\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nGet familiar with [NFT](https://docs.ton.org/standard/tokens/nft/overview) in TON.\n[Here](https://github.com/ton-blockchain/nft-contract) you can also look at the reference implementation of NFT (\nnon-fungible token) smart contract for TON.\n\n### Mint NFT collection\n\nFor a quick demonstration we use `GenerateWallet.randomV3R1()` method that creates a WalletV3R1 smart contract with a\nrandom private key in a testnet and tops it up automatically.\n\nFirstly, you have to create an NFT collection and then mint NFT items.\n\n```java\nAdnlLiteClient adnlLiteClient = AdnlLiteClient.builder().testnet().build();\n\nWalletV3R1 adminWallet = GenerateWallet.randomV3R1(adnlLiteClient, 7);\nlog.info(\"admin wallet address {}\", adminWallet.getAddress());\n\n// define NFT collection\nNftCollection nftCollection =\n  NftCollection.builder()\n    .tonProvider(adnlLiteClient)\n    .adminAddress(adminWallet.getAddress())\n    .royalty(0.13)\n    .royaltyAddress(adminWallet.getAddress())\n    .collectionContentUri(\"https://raw.githubusercontent.com/ton-blockchain/ton4j/main/1-media/nft-collection.json\")\n    .collectionContentBaseUri(\"https://raw.githubusercontent.com/ton-blockchain/ton4j/main/1-media/\")\n    .nftItemCodeHex(WalletCodes.nftItem.getValue())\n    .build();\n\nlog.info(\"NFT collection address {}\", nftCollection.getAddress());\n\n// deploy NFT Collection\nWalletV3Config adminWalletConfig =\n  WalletV3Config.builder()\n    .walletId(42)\n    .seqno(adminWallet.getSeqno())\n    .destination(nftCollection.getAddress())\n    .amount(Utils.toNano(1))\n    .stateInit(nftCollection.getStateInit())\n    .build();\n\nadminWallet.send(adminWalletConfig);\n```\n\n### Mint NFT item\n\n```java\nadminWalletConfig =\n  WalletV3Config.builder()\n    .walletId(42)\n    .seqno(adminWallet.getSeqno())\n    .destination(nftCollection.getAddress())\n    .amount(Utils.toNano(1))\n    .body(NftCollection.createMintBody(\n            0,  // query id \n            0,  // NFT index in collection\n            Utils.toNano(0.006), // amount forwarded to cover its initial balance/fees. \n            adminWallet.getAddress(), // nftItemOwnerAddress\n            \"nft-item-1.json\")) // nftItemContentUri\n    .build();\n\n// deploying NFT item #1\nadminWallet.send(adminWalletConfig);\n```\n\n### Get NFT information\n\n```java\nCollectionData data = nftCollection.getCollectionData();\nlog.info(\"nft collection itemsCount {}\", data.getItemsCount());\nlog.info(\"nft collection nextItemIndex {}\", data.getNextItemIndex());\nlog.info(\"nft collection owner {}\", data.getOwnerAddress());\nAddress nftItemAddress = nftCollection.getNftItemAddressByIndex(BigInteger.ZERO);\nlog.info(\"address at index 0 = {}\", nftItemAddress);\nlog.info(\"nft collection royalty params {}\", nftCollection.getRoyaltyParams());\n```\n\n### Transfer NFT\n\n```java\nadminWalletConfig =\n  WalletV3Config.builder()\n    .walletId(42)\n    .seqno(adminWallet.getSeqno())\n    .destination(nftItemAddress)\n    .amount(Utils.toNano(0.1))\n    .body(NftItem.createTransferBody(1, Address.of(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\"), BigInteger.ONE, null, null))\n    .build();\nadminWallet.send(adminWalletConfig); \n```\n\n### Change NFT collection owner\n\n```java\nadminWalletConfig =\n  WalletV3Config.builder()\n    .walletId(42)\n    .seqno(adminWallet.getSeqno())\n    .destination(nftCollection.getAddress())\n    .amount(Utils.toNano(0.055))\n    .body(NftCollection.createChangeOwnerBody(0, Address.of(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\")))\n    .build();\nadminWallet.send(adminWalletConfig);\n```\n\n### Edit NFT collection content\n\n```java\nadminWalletConfig =\n  WalletV3Config.builder()\n    .walletId(42)\n    .seqno(adminWallet.getSeqno())\n    .destination(nftCollection.getAddress())\n    .amount(Utils.toNano(0.055))\n    .body(NftCollection.createEditContentBody(0, \"ton://my-new-nft/collection.json\", \"ton://my-new-nft/\",0.005, Address.of(\"newRoyaltyAddress\")))\n    .build();\nadminWallet.send(adminWalletConfig);\n```\n\n### Create your own NFT marketplace\n\n```java\nNftMarketplace marketplace = NftMarketplace.builder().adminAddress(adminWallet.getAddress()).build();\nWalletV3Config adminWalletConfig =\n  WalletV3Config.builder()\n    .walletId(42)\n    .seqno(adminWallet.getSeqno())\n    .destination(marketplace.getAddress())\n    .amount(Utils.toNano(1))\n    .stateInit(marketplace.getStateInit())\n    .build();\nadminWallet.send(adminWalletConfig);\n```\n\n### Sell NFT\n\nUsing the above-created marketplace, you can deploy NFT items to it and sell them for TON.\n\n```java\n// create NFT Sale smart contract\nNftSale nftSale =\n  NftSale.builder()\n    .tonProvider(adnlLiteClient)\n    .marketplaceAddress(marketplace.getAddress())\n    .nftItemAddress(nftItemAddress) // your NFT item address\n    .fullPrice(Utils.toNano(1.1))\n    .marketplaceFee(Utils.toNano(0.4))\n    .royaltyAddress(nftCollection.getAddress())\n    .royaltyAmount(Utils.toNano(0.3))\n    .build();\nlog.info(\"nft-sale address {}\", nftSale.getAddress());\n\n// deploy NFT sale smart contract on a marketplace from the admin wallet\nCell body = CellBuilder.beginCell()\n  .storeUint(1, 32)\n  .storeCoins(Utils.toNano(0.06))\n  .storeRef(nftSale.getStateInit().toCell())\n  .storeRef(CellBuilder.beginCell().endCell())\n  .endCell();\n\nWalletV3Config adminWalletConfig = WalletV3Config.builder()\n  .walletId(42)\n  .seqno(adminWallet.getSeqno())\n  .destination(marketplace.getAddress())\n  .amount(Utils.toNano(0.06))\n  .body(body)\n  .build();\nadminWallet.send(adminWalletConfig);\n\n// now transfer your NFT to NFT sale smart contract\nadminWalletConfig = WalletV3Config.builder()\n    .walletId(42)\n    .seqno(wallet.getSeqno())\n    .destination(nftItemAddress)\n    .amount(msgValue)\n    .body(NftItem.createTransferBody(BigInteger.ONE, nftSale.getAddress(), BigInteger.ONE, forwardPayload, Address.of(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\")))\n    .build();\nadminWallet.send(adminWalletConfig); \n```\n\n### Cancel NFT sale\n\nWhen a user cancels the sale of his NFT item, the NFT item automatically moves from the NFT Sale smart contract back to\nadminWallet,\nand the NFT Sale smart contract becomes uninitialized.\n\n```java\nWalletV3Config adminWalletConfig = WalletV3Config.builder()\n  .walletId(42)\n  .seqno(adminWallet.getSeqno())\n  .destination(nftSale.getAddress())\n  .amount(Utils.toNano(0.055))\n  .body(NftSale.createCancelBody(queryId))\n  .build();\nadminWallet.send(adminWalletConfig);\n```\n\n### Buy NFT\n\nLet's buy our NFT item from the marketplace. Below the `NftItemBuyer` is the wallet that buys the NFT item.\n\n```java\nWalletV3Config nftItemBuyerWalletV3Config =  WalletV3Config.builder()\n  .walletId(42)\n  .seqno(nftItemBuyer.getSeqno())\n  .destination(nftSale.getAddress())\n  .amount(Utils.toNano(1.2 + 1)) // fullPrice + minimalGasAmount (1ton) todo\n  .build();\nnftItemBuyer.send(nftItemBuyerWalletV3Config);\n```\n\nMore examples on how to work with NFT\nin [tests](smartcontract/src/test/java/org/ton/ton4j/smartcontract/integrationtests/TestNft.java).\n\n## Jettons\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003esmartcontract\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003eadnl\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003eutils\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nGet familiar with [Jetton](https://docs.ton.org/standard/tokens/jettons/overview) in TON.\n[Here](https://github.com/ton-blockchain/jetton-contract) you can also look at the reference implementation of Jetton V2\nsmart contract for TON.\n\n### Create USDT jetton wallet\n\nLoad your keypair from either mnemonic or hex private key.\nYou also need to know a subwallet ID of your wallet, you need it for wallets of version V4 and V5.\nYou can get either by running `get_subwallet_id` on smart contract or using online explorers\nlike [tonviewer.com](tonviewer.com) or [tonscan.org](tonviewer.com), go to section `methods` and enter method name\n`get_subwallet_id`.\n\n```java\n// load your secret phrase\nTweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(Mnemonic.toKeyPair(\"your-secret-phrase\").getSecretKey());\n\n// or specify it hex format\n//byte[] secretKey = Utils.hexToSignedBytes(\"your-hex-secret-key\");\n// use when you have 64 bytes private key\n//TweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSecretKey(secretKey);\n// use when you have 32 bytes private key\n//TweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(secretKey);\n\nAdnlLiteClient adnlLiteClient = AdnlLiteClient.builder().mainnet().build();\n\n// define your wallet\nWalletV5 myWallet = WalletV5.builder().tonProvider(adnlLiteClient).keyPair(keyPair).walletId(\"your-subwallet-id\").isSigAuthAllowed(true).build();\nlog.info(\"myWallet address: {}\", myWallet.getAddress().toBounceable());\n\n// this is your USDT jetton wallet address\nlog.info(\"myJettonWallet address: {}\", myWallet.getUsdtWalletAddressOffline().toBounceable());\nlog.info(\"myJettonWallet address: {}\", myWallet.getUsdtWalletAddressOffline().toRaw());\n\n// usdt balance\nlog.info(\"myJettonWallet balance: {}\", myWallet.getUsdtBalance());\n\n// you can get the same jetton's details using online methods\nJettonWallet myJettonWallet = myWallet.getUsdtWallet();\n//\nlog.info(\"myJettonWallet address: {}\", myJettonWallet.getAddress().toBounceable());\nlog.info(\"myJettonWallet address: {}\", myJettonWallet.getAddress().toRaw());\nlog.info(\"myJettonWallet balance: {}\", myJettonWallet.getBalance());\n\n// you can also get a balance of any jetton, not only usdt.\nlog.info(\"balance: {}\",\n  ContractUtils.getJettonBalance(\n    adnlLiteClient,\n    address.of(\"EQAvlWFDxGF2lXm67y4yzC17wYKD9A0guwPkMs1gOsM__NOT\"), // jetton's minter address, e.g. NOT coin\n    myWallet.getAddress()));\n\n```\n\n### Transfer USDT to a single wallet\n\nContinuing the above example, transfer USDT to a single user\n\n```java\nWalletV5Config myWalletConfig =\n  WalletV5Config.builder()\n    .walletId(\"your-subwallet-id\")\n    .seqno(myWallet.getSeqno())\n    .amount(Utils.toNano(0.01))\n    .recipients(\n      Collections.singletonList(\n        Destination.builder()\n          .bounce(true)\n          .address(myJettonWallet.getAddress().toBounceable())\n          .sendMode(SendMode.PAY_GAS_SEPARATELY_AND_IGNORE_ERRORS)\n          .amount(Utils.toNano(0.05))\n          .body(JettonWallet.createTransferBody(\n            0, // query id\n            Utils.toUsdt(0.1), // $0.1, number of jettons\n            Address.of(\"recipient-address\"), // recipient\n            myJettonWallet.getAddress(), // response address\n            null, // custom payload\n            BigInteger.ONE, // forward amount\n            MsgUtils.createTextMessageBody(\"v5-jetton-tx-demo\"))) // forward payload\n          .build()))\n          .build();\nSendResponse sendResponse = myWallet.send(myWalletConfig);\nlog.info(\"sendResponse: {}\", sendResponse);\n```\n\n### Transfer USDT to multiple wallets\n\n```java\nWalletV5Config myWalletConfig =\n  WalletV5Config.builder()\n    .walletId(2147483409)\n    .seqno(myWallet.getSeqno())\n    .amount(Utils.toNano(0.01))\n    .recipients(List.of(\n      Destination.builder()\n        .bounce(true)\n        .address(myJettonWallet.getAddress().toBounceable())\n        .sendMode(SendMode.PAY_GAS_SEPARATELY_AND_IGNORE_ERRORS)\n        .amount(Utils.toNano(0.05))\n        .body(JettonWallet.createTransferBody(\n          0,\n          Utils.toUsdt(0.01), // $0.1\n          Address.of(\"recipient-1\"), // recipient\n          myJettonWallet.getAddress(), // response address\n          null, // custom payload\n          BigInteger.ONE, // forward amount\n          MsgUtils.createTextMessageBody(\"v5-jetton-tx-demo\") ))// forward payload\n        .build(),\n      Destination.builder()\n        .bounce(true)\n        .address(myJettonWallet.getAddress().toBounceable())\n        .sendMode(SendMode.PAY_GAS_SEPARATELY_AND_IGNORE_ERRORS)\n        .amount(Utils.toNano(0.05))\n        .body(JettonWallet.createTransferBody(\n          0,\n          Utils.toUsdt(0.01), // $0.1\n          Address.of(\"recipient-2\"), // recipient\n          myJettonWallet.getAddress(), // response address\n          null, // custom payload\n          BigInteger.ONE, // forward amount\n          MsgUtils.createTextMessageBody(\"v5-jetton-tx-demo\") ))// forward payload\n        .build(),\n      Destination.builder()\n        .bounce(true)\n        .address(myJettonWallet.getAddress().toBounceable())\n        .sendMode(SendMode.PAY_GAS_SEPARATELY_AND_IGNORE_ERRORS)\n        .amount(Utils.toNano(0.05))\n        .body(JettonWallet.createTransferBody(\n          0,\n          Utils.toUsdt(0.01), // $0.1\n          Address.of(\"recipient-3\"), // recipient\n          myJettonWallet.getAddress(), // response address\n          null, // custom payload\n          BigInteger.ONE, // forward amount\n          MsgUtils.createTextMessageBody(\"v5-jetton-tx-demo\") ))// forward payload\n        .build(),\n      Destination.builder()\n        .bounce(true)\n        .address(myJettonWallet.getAddress().toBounceable())\n        .sendMode(SendMode.PAY_GAS_SEPARATELY_AND_IGNORE_ERRORS)\n        .amount(Utils.toNano(0.05))\n        .body(JettonWallet.createTransferBody(\n          0,\n          Utils.toUsdt(0.01), // $0.1\n          Address.of(\"recipient-4\"), // recipient\n          myJettonWallet.getAddress(), // response address\n          null, // custom payload\n          BigInteger.ONE, // forward amount\n          MsgUtils.createTextMessageBody(\"v5-jetton-tx-demo\") ))// forward payload\n        .build(),\n      Destination.builder()\n        .bounce(true)\n        .address(myJettonWallet.getAddress().toBounceable())\n        .sendMode(SendMode.PAY_GAS_SEPARATELY_AND_IGNORE_ERRORS)\n        .amount(Utils.toNano(0.05))\n        .body(JettonWallet.createTransferBody(\n          0,\n          Utils.toUsdt(0.01), // $0.1\n          Address.of(\"recepient-5\"), // recipient\n          myJettonWallet.getAddress(), // response address\n          null, // custom payload\n          BigInteger.ONE, // forward amount\n          MsgUtils.createTextMessageBody(\"v5-jetton-tx-demo\") ))// forward payload\n        .build()\n      ))\n  .build();\nSendResponse sendResponse = myWallet.send(myWalletConfig);\nlog.info(\"sendResponse: {}\", sendResponse);\n```\n\n### Mint Jetton\n\n```java\nTonProvider adnlLiteClient = AdnlLiteClient.builder().testnet().liteServerIndex(2).build();\nadminWallet = GenerateWallet.randomV4R2(adnlLiteClient, 2);\nnextAdminWallet = GenerateWallet.randomV4R2(adnlLiteClient, 1);\n\nlog.info(\"admin wallet address {}\", adminWallet.getAddress());\nlog.info(\"next admin wallet address {}\", nextAdminWallet.getAddress());\n\nJettonMinterV2 minter =\n  JettonMinterV2.builder()\n    .tonProvider(adnlLiteClient)\n    .adminAddress(adminWallet.getAddress())\n    .nextAdminAddress(nextAdminWallet.getAddress())\n    .content(\n      CellBuilder.beginCell()\n        .storeSnakeString(\n            \"https://raw.githubusercontent.com/ton-blockchain/ton4j/main/1-media/neo-jetton.json\")\n        .endCell())\n  .build();\n\n    log.info(\"jetton minter address {}\", minter.getAddress());\n\n// deploy jetton minter contract from the admin wallet\nWalletV4R2Config walletV4Config =\n        WalletV4R2Config.builder()\n                .walletId(42)\n                .seqno(adminWallet.getSeqno())\n                .destination(minter.getAddress())\n                .amount(Utils.toNano(0.2))\n                .stateInit(minter.getStateInit())\n                .comment(\"deploy minter\")\n                .build();\n\nSendResponse sendResponse = adminWallet.send(walletV4Config);\nlog.info(\"sendResponse {}\", sendResponse);\nlog.info(\"deploying minter...\");\nminter.waitForDeployment();\n\n// mint jettons\nwalletV4Config =\n  WalletV4R2Config.builder()\n    .walletId(42)\n    .seqno(adminWallet.getSeqno())\n    .destination(minter.getAddress())\n    .amount(Utils.toNano(0.1))\n    .body(JettonMinterV2.createMintBody(\n        0, // query id\n        adminWallet.getAddress(),\n        Utils.toNano(0.1),\n        100500, // number of jettons to mint, mind the decimal point\n        null, // from address\n        null, // response address\n        BigInteger.ONE,\n        MsgUtils.createTextMessageBody(\"minting\")))\n.build();\n\nsendResponse = adminWallet.send(walletV4Config);\nlog.info(\"sendResponse {}\", sendResponse);\nlog.info(\"minting...\");\n```\n\n### Get Jetton information\n\n```java\nJettonMinterData data = minter.getJettonData();\nlog.info(\"minter adminAddress {} {}\", data.getAdminAddress(), data.getAdminAddress().toRaw());\nlog.info(\"minter totalSupply {}\", data.getTotalSupply());\nlog.info(\"minter jetton content cell {}\", data.getJettonContentCell());\n```\n\n### Edit minter jetton content\n\n```java\nwalletV4Config =\n    WalletV4R2Config.builder()\n        .walletId(42)\n        .seqno(adminWallet.getSeqno())\n        .destination(minter.getAddress())\n        .amount(Utils.toNano(0.05))\n        .body(JettonMinterV2.createChangeMetaDataUriBody(\n                \"http://localhost/nft-marketplace/my_collection_1.json\", 0))\n        .build();\nsendResponse = adminWallet.send(walletV4Config);\nlog.info(\"sendResponse {}\", sendResponse);\n```\n\n### Edit jetton admin address\n\n```java\nwalletV4Config =\n    WalletV4R2Config.builder()\n        .walletId(42)\n        .seqno(adminWallet.getSeqno())\n        .destination(minter.getAddress())\n        .amount(Utils.toNano(0.05))\n        .body(JettonMinterV2.createChangeAdminBody(0, Address.of(\"NEW_ADMIN_ADDRESS\")))\n        .build();\nsendResponse = adminWallet.send(walletV4Config);\nlog.info(\"send response {}\", sendResponse);\n```\n\n### Transfer jetton\n\n```java\nwalletV4Config =\n    WalletV4R2Config.builder()\n    .walletId(42)\n    .seqno(adminWallet.getSeqno())\n    .destination(adminJettonWallet.getAddress())\n    .amount(Utils.toNano(0.05))\n    .body(JettonWalletV2.createTransferBody(\n        0,\n        444, // number of jettons to transfer\n        Address.of(\"recipient-address\"), // recipient\n        null, // response address\n        null, // custom payload\n        BigInteger.ONE, // forward amount\n        MsgUtils.createTextMessageBody(\"gift\"))) // forward payload\n        .build();\nsendResponse = adminWallet.send(walletV4Config);\nassertThat(sendResponse.getCode()).isZero();\n\nUtils.sleep(5, \"transferring 444 jettons...\");\nlog.info(\"admin balance {}\", Utils.formatNanoValue(adminJettonWallet.getBalance()));\n```\n\n### Burn jettons\n\n```java\nwalletV4Config =\n    WalletV4R2Config.builder()\n    .walletId(42)\n    .seqno(adminWallet.getSeqno())\n    .destination(adminJettonWallet.getAddress())\n    .amount(Utils.toNano(0.05))\n    .body(JettonWalletV2.createBurnBody(\n             0,    // query id\n             111), // number of jettons to burn \n           adminWallet.getAddress()))\n    .build();\nsendResponse = adminWallet.send(walletV4Config);\nlog.info(\"sendResponse {}\", sendResponse);\n```\n\nMore examples on how to mint Jettons, as well as administrate them, can be found\nin [tests](smartcontract/src/test/java/org/ton/ton4j/smartcontract/integrationtests/TestJettonV2.java).\n\n## DNS\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003esmartcontract\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nWith the help of `ton4j` you can resolve DNS name of any site or wallet.\nYou can even deploy your own DNS resolution smart contract, also called a root DNS contract.\nIn TON blockchain DNS names are NFT items, means you can deploy a collection of names, sell, buy, change and transfer\nthem.\n\n### Resolve DNS records\n\nIn the mainnet using AdnlLiteClient\n\n```java\nAdnlLiteClient adnlLiteClient = \n  AdnlLiteClient.builder()\n    .configUrl(Utils.getGlobalConfigUrlTestnetGithub())\n    .build();\n\nDns dns = Dns.builder().tonProvider(adnlLiteClient).build();\nAddress rootAddress = dns.getRootDnsAddress();\nlog.info(\"root DNS address = {}\", rootAddress.toBounceable());\n\nObject result = dns.resolve(\"apple.ton\");\nlog.info(\"apple.ton resolved to {}\", ((Address) result).toBounceable());\n\nAddress addr = (Address) dns.getWalletAddress(\"foundation.ton\");\nlog.info(\"foundation.ton resolved to {}\", addr.toBounceable());\n\nAddress addr = (Address) dns.getSiteAddress(\"foundation.ton\");\nlog.info(\"foundation.ton resolved to {}\", addr.toBounceable());\n```\n\n### Deploy own root DNS\n\nBefore deploying root DNS smart contract, you have to deploy three NFT collections:\n\n- address of \".ton\" dns resolver smart contract in basechain\n- address of \".t.me\" dns resolver smart contract in basechain\n- address of \"www.ton\" dns resolver smart contract in basechain\n\n```java\nWalletV3R1 adminWallet = GenerateWallet.randomV3R1(tonlib, 1);\n\nDnsRoot dnsRootContract =\n  DnsRoot.builder()\n    .tonProvider(tonlib)\n    .wc(0)\n    .keyPair(adminWallet.getKeyPair())\n    .address1(\"address-of-nft-collection-for .ton\")\n    .address2(\"address-of-nft-collection-for .t.me\")\n    .address3(\"address-of-nft-collection-for .www.ton\")        \n    .build();\nlog.info(\"new root DNS address {}\", dnsRootContract.getAddress());\n\nWalletV3Config adminWalletConfig =\n  WalletV3Config.builder()\n    .walletId(42)\n    .seqno(1)\n    .destination(dnsRootContract.getAddress())\n    .amount(Utils.toNano(0.12))\n    .stateInit(dnsRootContract.getStateInit())\n    .build();\n\nSendResponse sendResponse = adminWallet.send(adminWalletConfig);\nassertThat(sendResponse.getCode()).isZero();\n\ndnsRootContract.waitForDeployment();\n\nassertThat(dnsRootContract.isDeployed()).isTrue();\n```\n\nMore DNS examples on how to deploy a DNS collection and manipulate DNS items\nsee [here](smartcontract/src/test/java/org/ton/ton4j/smartcontract/integrationtests/TestDns.java).\n\n## Smart Contracts\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n  \u003cartifactId\u003esmartcontract\u003c/artifactId\u003e\n  \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003eadnl\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n    \u003cartifactId\u003eutils\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nYou can fetch contract's data either by using directly TonProvider client or by calling ready-to-use getters of various\nwallet contracts.\n\n### Using GET methods from TON providers\n\n#### AdnlLiteClient run method usage\n\nUse AdnlLiteClient's `runMethod` to specify contract's address, method name and parameters\n\n```java\n// for the latest block\npublic RunMethodResult runMethod(Address accountAddress, String methodName, VmStackValue... params);\n// for the particular block in the past\npublic RunMethodResult runMethod(BlockIdExt id, int mode, Address accountAddress, long methodId, byte[] methodParams)\n```\n\nbelow example shows how to call V4R2 contract's method `is_plugin_installed` with two parameters:\n\n```java\nRunMethodResult runMethodResult =\n  ((AdnlLiteClient) provider)\n    .runMethod(\n      \"your-wallet-v4-address\",\n      \"is_plugin_installed\",\n      VmStackValueInt.builder().value(BigInteger.valueOf(pluginAddress.wc)).build(),\n      VmStackValueInt.builder().value(new BigInteger(hashPart)).build());\n\nreturn runMethodResult.getIntByIndex(0).intValue() != 0;\n```\n\nSimilar run methods are available in Tonlib and TonCenter providers\n\n#### Tonlib run method usage\n\n```java\npublic RunResult runMethod(Address contractAddress, String methodName);\npublic RunResult runMethod(Address contractAddress, String methodName, BlockIdExt blockId);\n//example of calling get_public_key\nRunResult result = ((Tonlib) provider).runMethod(getAddress(), \"get_public_key\");\n```\n\n#### TonCenter run method usage\n\n```java\npublic TonResponse\u003cRunGetMethodResponse\u003e runGetMethod(String address, Object method, List\u003cList\u003cObject\u003e\u003e stack);\npublic TonResponse\u003cRunGetMethodResponse\u003e runGetMethod(String address, Object method, List\u003cList\u003cObject\u003e\u003e stack, Long seqno);\n\n// example of calling wallet_id\nTonResponse\u003cRunGetMethodResponse\u003e r = ((TonCenter) provider).runGetMethod(getAddress().toBounceable(), \"wallet_id\", new ArrayList\u003c\u003e());\n```\n\n### Using GET methods\n\n`ton4j` provides Java classes for standard wallets, like `Multisig`, `Highload`, `V3R2` etc.\nAll of them have many ready-to-use helpful methods for standard methods, like `seqno`, `wallet_id`, `get_public_key`.\nSome have specific methods only relevant for that contract, e.g. V4R2 has: `isPluginInstalled`, `getPluginsList`,\n`getSubscriptionData`, `installPlugin`, `uninstallPlugin`.\n\n### Develop custom smart contract\n\nYou can also develop TON smart contracts with a help of `SmartContractCompiler`.\n`SmartContractCompiler` supports `tolk` and `func` compilers, and uses `GenericSmartContract` as a smart-contract\nwrapper with basis methods for deployment.\n\n#### Compile\n\nIf your contract has imports and dependencies on other files,\nspecify the top-level contract and make sure other files are available from the same directory.\n\nAssume you have a custom smart contract written in Tolk\n\u003cdetails\u003e\n  \u003csummary\u003eSimple contract\u003c/summary\u003e\n\n```java\nimport \"@stdlib/gas-payments\"\ntolk 1.1\n\nstruct Storage {\n  id: uint32\n  counter: uint32\n}\n\nfun Storage.load() {\n  return Storage.fromCell(contract.getData())\n}\n\nfun Storage.save(self) {\n  contract.setData(self.toCell())\n}\n\nstruct (0x7e8764ef) IncreaseCounter {\n  queryId: uint64  // query id, typically included in messages\n  increaseBy: uint32\n}\n\nstruct (0x3a752f06) ResetCounter {\n  queryId: uint64\n}\n\ntype AllowedMessage = IncreaseCounter | ResetCounter\n\nfun onExternalMessage(extBody: slice) {\n  var storage = lazy Storage.load();\n  val msgId = extBody.loadUint(32);\n  val counter = extBody.loadUint(32);\n  assert (msgId == storage.id) throw 33;\n  acceptExternalMessage();\n  storage.id += 1;\n  storage.counter = counter;\n  storage.save();\n}\n\nfun onInternalMessage(in: InMessage) {\nval msg = lazy AllowedMessage.fromSlice(in.body);\n    match (msg) {\n        IncreaseCounter =\u003e {\n            var storage = lazy Storage.load();\n            storage.counter += msg.increaseBy;\n            storage.save();\n        }\n\n        ResetCounter =\u003e {\n            var storage = lazy Storage.load();\n            storage.counter = 0;\n            storage.save();\n        }\n\n        else =\u003e {\n            assert (in.body.isEmpty()) throw 0xFFFF\n        }\n    }\n}\n\nfun onBouncedMessage(in: InMessageBounced) {\n}\n\nget fun currentCounter(): int {\n  val storage = lazy Storage.load();\n  return storage.counter;\n}\n\nget fun initialId(): int {\n  val storage = lazy Storage.load();\n  return storage.id;\n}\n```\n\n\u003c/details\u003e\n\nNow let's compile it\n\n```java\n// create Tolk\nTolkRunner tolkRunner =\n  TolkRunner.builder()\n    .tolkExecutablePath(Utils.getTolkGithubUrl())                \n    .build();\n// assign Tolk to SmartContractCompiler\nSmartContractCompiler smartContractCompiler =\n  SmartContractCompiler.builder()\n    .tolkRunner(tolkRunner)\n    .contractPath(\"/home/user/smart-contract/simple.tolk\")\n    .build();\n// compile and get a code cell as a BoC\nString codeBocHex = smartContractCompiler.compile();\nlog.info(\"codeBocHex {}\", codeBocHex);\n```\n\n#### Deploy\n\nEvery smart contract in the TON ecosystem consists of its code and data (storage), thus you have to provide both during\nthe deployment.\nIf your smart contract does not use storage, you can have an empty data cell.\n\nIn the example below let's use [MyLocalTon Docker](https://github.com/neodix42/mylocalton-docker) or\n[MyLocalTon Desktop](https://github.com/neodix42/mylocalton) app for deployment, instead of deploying to testnet or\nmainnet.\nBoth Docker and Desktop versions of MyLocalTon on start expose a global config that can be used by Ton providers.\nThe URL for the config is always the same:  http://127.0.0.1:8000/localhost.global.config.json\n\nDeploy the above compiled smart contract\n\n```java\n// initialize a TON provider as a Tonlib client connected to MyLocalTon\nTonlib tonlib =\n  Tonlib.builder()\n    .pathToGlobalConfig(\"http://127.0.0.1:8000/localhost.global.config.json\")\n    .pathToTonlibSharedLib(Utils.getTonlibGithubUrl())\n    .ignoreCache(false)\n    .build();\n\n// define smart contract's initial data (storage) values \nString dataCellHex =\n    CellBuilder.beginCell()\n        .storeUint(4, 32) // id\n        .storeUint(5, 32) // counter\n        .endCell()\n        .toHex();\n\nGenericSmartContract genericSmartContract =\n  GenericSmartContract.builder()\n    .code(codeBocHex)\n    .data(dataCellHex)\n    .tonProvider(tonlib)\n    .build();\n\nAddress address = genericSmartContract.getAddress();\nBigInteger balance = TestnetFaucet.topUpContract(tonlib, address, Utils.toNano(0.1));\nlog.info(\"balance genericSmartContract: {}\", Utils.formatNanoValue(balance));\n\n//deploy\nSendResponse sendResponse = genericSmartContract.deployWithoutSignature(CellBuilder.beginCell().storeUint(4, 32).endCell());\nlog.info(\"sendResponse {}\", sendResponse);\nassertThat(sendResponse.getCode()).isZero();\ntonlib.waitForDeployment(address);\n\n// get currentCounter value\nRunResult runResult = tonlib.runMethod(address, \"currentCounter\");\nlong currentCounter = ((TvmStackEntryNumber) runResult.getStack().get(0)).getNumber().longValue();\nlog.info(\"currentCounter {}\", currentCounter);\n```\n\n## BitString\n\n`BitString` used to construct an array of bits, and later read out of it.\nBitString may contain up to 1023 bits, which is the maximum size of a cell.\nOnce you write anything to a BitString, it shifts the writing cursor and subsequent writes will be appended it.\nThe same happens when you read data from a BitString, it moves reading cursor forward.\n\nConstruct and read a BitString\n\n```java\n// write\nBitString bitString = new BitString(3);\nbitString.writeUint(7, 3);\nassertThat(bitString.toBitString()).isEqualTo(\"111\");\n// read\nbitString.readUint(3); // returns 7\n```\n\nWrite signed integers (int)\n\n```java\nBitString bitString = new BitString(32);\nbitString.writeInt(BigInteger.valueOf(200), 9);\nassertThat(bitString.toBitString()).isEqualTo(\"011001000\");\nassertThat(bitString.toHex()).isEqualTo(\"644_\");\n\nBitString bitStringMax64 = new BitString(64); // Long.MAX_VALUE, 8 bytes\nbitStringMax64.writeInt(new BigInteger(\"9223372036854775807\"), 64);\nassertThat(bitStringMax64.toBitString()).isEqualTo(\"0111111111111111111111111111111111111111111111111111111111111111\");\n\nBitString bitStringMax128 = new BitString(128);\nbitStringMax128.writeInt(new BigInteger(\"92233720368547758070\"), 128);\nassertThat(bitStringMax128.toBitString()).isEqualTo(\"00000000000000000000000000000000000000000000000000000000000001001111111111111111111111111111111111111111111111111111111111110110\");\n\nBitString bitStringMaxA = new BitString(128);\nbitStringMaxA.writeInt(new BigInteger(\"99999999999999999999999999999999999999\"), 128);\nassertThat(bitStringMaxA.toBitString()).isEqualTo(\"01001011001110110100110010101000010110101000011011000100011110100000100110001010001000100011111111111111111111111111111111111111\");\n\nBigInteger i = bitStringMaxA.readInt(128);\nassertThat(i.toString(16).toUpperCase()).isEqualTo(\"4B3B4CA85A86C47A098A223FFFFFFFFF\");\n\nBitString bitStringMaxB = new BitString(256);\nbitStringMaxB.writeInt(new BigInteger(\"9999999999999999999999999999999999999999999999999999999999\"), 256);\nassertThat(bitStringMaxB.toHex()).isEqualTo(\"000000000000000197D4DF19D605767337E9F14D3EEC8920E3FFFFFFFFFFFFFF\");\n```\n\nWrite unsigned integers (uint)\n\n```java\nBitString bitString = new BitString(16);\nbitString.writeUint(BigInteger.valueOf(255), 8);\nassertThat(bitString.toBitString()).isEqualTo(\"11111111\");\nassertThat(bitString.toHex()).isEqualTo(\"FF\");\n\nbitString = new BitString(64);\nbitString.writeUint(BigInteger.valueOf(Long.MAX_VALUE), 64);\nassertThat(bitString.toBitString()).isEqualTo(\"0111111111111111111111111111111111111111111111111111111111111111\");\nassertThat(bitString.toHex()).isEqualTo(\"7FFFFFFFFFFFFFFF\");\n\nbitString = new BitString(128);\nbitString.writeUint(15, 4);\n```\n\nRead unsigned integers (uint)\n\n```java\nBitString bitString = new BitString(128);\nbitString.writeUint(200, 8);\nbitString.writeUint(400, 16);\nbitString.writeUint(600000, 32);\nbitString.writeUint(new BigInteger(\"9000000000000\"), 64);\n\nassertThat(bitString.readUint8().toString(10)).isEqualTo(\"200\");\nassertThat(bitString.readUint16().toString(10)).isEqualTo(\"400\");\nassertThat(bitString.readUint32().toString(10)).isEqualTo(\"600000\");\nassertThat(bitString.readUint64().toString(10)).isEqualTo(\"9000000000000\");\n```\n\nRead signed integers (int)\n\n```java\nBitString bitString = new BitString(128);\nbitString.writeInt(BigInteger.valueOf(20), 8);\nbitString.writeInt(BigInteger.valueOf(400), 16);\nbitString.writeInt(BigInteger.valueOf(600000), 32);\nbitString.writeInt(new BigInteger(\"9000000000000\"), 64);\n\nassertThat(bitString.readInt8().toString(10)).isEqualTo(\"20\");\nassertThat(bitString.readInt16().toString(10)).isEqualTo(\"400\");\nassertThat(bitString.readInt32().toString(10)).isEqualTo(\"600000\");\nassertThat(bitString.readInt64().toString(10)).isEqualTo(\"9000000000000\");\n```\n\nWrite mixed data type to BitString\n\n```java\nBitString bitString = new BitString(1023);\nbitString.writeInt(BigInteger.valueOf(-200), 16);\nbitString.writeUint(BigInteger.valueOf(200), 9);\nbitString.writeCoins(BigInteger.TEN);\nbitString.writeString(\"A\");\nAddress address = Address.of(\"0QAs9VlT6S776tq3unJcP5Ogsj-ELLunLXuOb1EKcOQi4-QO\");\nbitString.writeAddress(address);\n```\n\nYou can also get a number of `free` and `used` bits using `getFreeBits` and `getUsedBits` methods.\n\nThere are lots of helpful methods, like `writeAddress`, `writeCoins`, `writeUint8`, `writeBytes`, `readBit`, `readBits`\netc.\n\nMore examples in [tests](bitstring/src/test/java/org/ton/ton4j/bitstring).\n\n## Cells\n\nThe TON Virtual Machine (TVM) memory, persistent storage, and smart contract code consist of cells.\n\n[Get familiar with the Cell concept in the official documentation.](https://docs.ton.org/foundations/serialization/cells#cells)\n\n### Cell Builder\n\n`CellBuilder` class helps to construct TON cell out of primitives as well as\nfrom [Bag of Cells (BoC)](https://docs.ton.org/foundations/serialization/boc).\n\nConstruct ordinary Cell using CellBuilder with various types of data\n\n```java\nCell cell1 =\n  CellBuilder.beginCell()\n  .storeBytes(new byte[] {65, 66, 67})\n  .storeUint(new BigInteger(\"538bd272cc81b9d5f470a18a946cbb8fb621ca57593836014e0f12fd5d34942f\", 16), 256)\n  .storeString(\"test sdk\")\n  .endCell();\n\nCell cell2 =\n  CellBuilder.beginCell()\n  .storeInt(new BigInteger(\"568E7E73CDA9C3D5FF8641E77EED4EE65EDB702EA100290F2E7A043771C9CA5A\", 16), 256)\n  .storeCoins(Utils.toNano(\"2.56\"))\n  .storeAddress(Address.of(\"0QAljlSWOKaYCuXTx2OCr9P08y40SC2vw3UeM1hYnI3gDY7I\"))\n  .storeRef(cell1)\n  .endCell();\n\nlog.info(\"cell2 {}\", cell2.print());\n// serialize cell to BoC\nbyte[] boc = cell2.toBoc(true);\n```\n\nConstruct Merkle Proof Cell Type\n\n```java\nCell c =\n  CellBuilder.beginCell()\n    .storeUint(3, 8) // Merkle Proof Cell Type\n    .storeBytes(mc.getHash())\n    .storeUint(mc.getDepthLevels()[0], 16)\n    .storeRef(mc)\n    .cellType(CellType.MERKLE_PROOF)\n    .setExotic(true)\n    .endCell();\n```\n\nConstruct Pruned Cell Type\n\n```java\nCell c =\n  CellBuilder.beginCell()\n    .storeUint(1, 8) // Merkle Proof Cell Type\n    .storeBytes(mc.getHash())\n    .storeUint(mc.getDepthLevels()[0], 16)\n    .storeRef(mc)\n    .setExotic(true)\n    .cellType(CellType.PRUNED_BRANCH)\n    .endCell();\n```\n\n### Cell Serialization\n\nTo serialize a Cell means to transform it into BoC format.\n\nTo serialize any Cell you have to use `toBoc()` method, e.g.:\n\n```java\nCell c1 = CellBuilder.beginCell().storeUint((long) Math.pow(2, 25), 26).endCell();\nCell c2 = CellBuilder.beginCell().storeUint((long) Math.pow(2, 37), 38).storeRef(c1).endCell();\nCell c3 = CellBuilder.beginCell().storeUint((long) Math.pow(2, 41), 42).endCell();\nCell c4 = CellBuilder.beginCell().storeUint((long) Math.pow(2, 42), 44).endCell();\nCell c5 =\n  CellBuilder.beginCell()\n    .storeAddress(Address.parseFriendlyAddress(\"0QAljlSWOKaYCuXTx2OCr9P08y40SC2vw3UeM1hYnI3gDY7I\"))\n    .storeString(\"HELLO\")\n    .storeRef(c2)\n    .storeRefs(c3, c4)\n    .endCell();\n\nassertThat(c5.getUsedRefs()).isEqualTo(3);\nbyte[] serializedCell5 = c5.toBoc(false);\n```\n\n### Cell Deserialization\n\nTo deserialize a Cell means to transform it to Cell from BoC format. BoC can be provided in a format of an array of\nbytes, hex or base64 string, e.g.:\n\n```java\nCell c = CellBuilder.beginCell().storeUint(42, 7).endCell();\nbyte[] serializedCell = c.toBoc(true);\nCell dc = CellBuilder.beginCell().fromBoc(serializedCell).endCell();\n```\n\nDeserialize BoC\n\n```java\nCell c = CellBuilder.beginCell()\n        .fromBoc(\"b5ee9c724101030100d700026fc00c419e2b8a3b6cd81acd3967dbbaf4442e1870e99eaf32278b7814a6ccaac5f802068148c314b1854000006735d812370d00764ce8d340010200deff0020dd2082014c97ba218201339cbab19f71b0ed44d0d31fd31f31d70bffe304e0a4f2608308d71820d31fd31fd31ff82313bbf263ed44d0d31fd31fd3ffd15132baf2a15144baf2a204f901541055f910f2a3f8009320d74a96d307d402fb00e8d101a4c8cb1fcb1fcbffc9ed5400500000000229a9a317d78e2ef9e6572eeaa3f206ae5c3dd4d00ddd2ffa771196dc0ab985fa84daf451c340d7fa\")\n        .endCell();\nlog.info(\"CellType {}\", c.getCellType());\nlog.info(c.toString());\nlog.info(\"length {}\", c.getBitLength());\n```\n\nMore examples on CellBuilder in [tests](cell/src/test/java/org/ton/ton4j/cell).\n\n### Cell Slice\n\n`CellSlice` used to parse Cell data\n\nLet's construct a Cell first\n\n```java\nBitString bs0 = new BitString(10);\n\nbs0.writeUint(40, 8);\n\nCell cRef0 = CellBuilder.beginCell().storeUint(1, 3).storeUint(100, 8).endCell();\nCell cRef1 = CellBuilder.beginCell().storeUint(2, 3).storeUint(200, 8).endCell();\n\nAddress addr = Address.of(\"0QAs9VlT6S776tq3unJcP5Ogsj-ELLunLXuOb1EKcOQi4-QO\");\n\nCell c0 =\n  CellBuilder.beginCell()\n    .storeUint(10, 8)\n    .storeUint(20, 8)\n    .storeInt(30, 8)\n    .storeRef(cRef0)\n    .storeRef(cRef1)\n    .storeBitString(bs0)\n    .storeAddress(addr)\n    .endCell();\n```\n\nand now let's extract data out of it using `CellSlice` class\n\n```java\nCellSlice cs0 = CellSlice.beginParse(c0);\n\nassertThat(cs0.loadUint(8).longValue()).isEqualTo(10);\nassertThat(cs0.loadUint(8).longValue()).isEqualTo(20);\nassertThat(cs0.loadUint(8).longValue()).isEqualTo(30);\n\nCellSlice csRef0 = CellSlice.beginParse(cs0.loadRef());\nCellSlice csRef1 = CellSlice.beginParse(cs0.loadRef());\n\nassertThat(csRef0.loadUint(3)).isEqualTo(1);\nassertThat(csRef0.loadUint(8)).isEqualTo(100);\nassertThat(cs0.loadUint(8).longValue()).isEqualTo(40);\nassertThat(csRef1.loadUint(3)).isEqualTo(2);\nassertThat(csRef1.loadUint(8)).isEqualTo(200);\nassertThat(cs0.loadAddress().toString(false)).isEqualTo(Address.of(\"0:2cf55953e92efbeadab7ba725c3f93a0b23f842cbba72d7b8e6f510a70e422e3\").toString(false));\n```\n\nAnother example of creating a Cell out of BoC and extracting uint value from it\n\n```java\nCell c1 = CellBuilder.beginCell().fromBoc(\"b5ee9c72410101010003000001558501ef11\").endCell();\nCellSlice cs = CellSlice.beginParse(c1);\nBigInteger i = cs.loadUint(7);\nassertThat(i.longValue()).isEqualTo(42);\ncs.endParse();\n```\n\n### Hashmaps\n\nThere are [several types of Hashmaps](https://docs.ton.org/foundations/whitepapers/tvm#3-3-hashmaps-or-dictionaries) (\nalso called Dicts) in TON.\n\n- **Hashmap** - fixed size keys, hashmap cannot be empty;\n- **HashmapE**- fixed size keys, hashmap can be empty;\n- **PfxHashmap** - variable size keys, hashmap cannot be empty and the keys cannot be prefixes of each other;\n- **PfxHashmapE** - variable size keys, hashmap can be empty;\n- **AugHashmap** - fixed size keys, hashmap cannot be empty. Similar to the Hashmap. However, each intermediate node of\n  the Patricia tree representing an augmented hashmap is augmented by a value of type Y.\n- **AugHashmapE** - fixed size keys, hashmap can be empty;\n- **VarHashmap** - variable size keys, hashmap cannot be empty, not supported by ton4j;\n- **VarHashmapE** - variable size keys, hashmap can be empty, not supported by ton4j;\n\n#### Serialization\n\nExample of serialization of TonHashMap with four elements\n\n```java\nTonHashMap x = new TonHashMap(9);\n\nx.elements.put(100L, (byte) 1);\nx.elements.put(200L, (byte) 2);\nx.elements.put(300L, (byte) 3);\nx.elements.put(400L, (byte) 4);\n\nCell dictCell =\n    x.serialize(\n        k -\u003e CellBuilder.beginCell().storeUint((Long) k, 9).endCell().getBits(),\n        v -\u003e CellBuilder.beginCell().storeUint((byte) v, 3).endCell());\n```\n\nAnother example of TonHashMapE serialization\n\n```java\nTonHashMapE x = new TonHashMapE(9);\n\nx.elements.put(100L, Address.of(\"0QAljlSWOKaYCuXTx2OCr9P08y40SC2vw3UeM1hYnI3gDY7I\"));\nx.elements.put(200L, Address.of(\"Uf-CRYz9HRGdb19t7DOZUfUjwUZmngz-zJvpD8vpmF3xqeXg\"));\nx.elements.put(300L, Address.of(\"UQCnuv+ZuR0QsIh5vwxUBuzzocSowbCa7ctdwl6QizBKzDiJ\"));\nx.elements.put(400L, Address.of(\"Ef8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM0vF\"));\n\nCell dictCell =\n    x.serialize(\n        k -\u003e CellBuilder.beginCell().storeUint((Long) k, 9).endCell().getBits(),\n        v -\u003e CellBuilder.beginCell().storeAddress((Address) v).endCell());\n```\n\n#### Deserialization\n\nWhen you deserialize Hashmap from Cell, you must pass deserialization methods (parsing rules) for keys and values.\n\nDeserialize Hashmap stored in BoC\n\n```java\nString boc = \"B5EE9C7241010501001D0002012001020201CF03040009BC0068054C0007B91012180007BEFDF218CFA830D9\";\n\nCell cellWithDict = CellBuilder.beginCell().fromBoc(boc).endCell();\n\nCellSlice cs = CellSlice.beginParse(cellWithDict);\nTonHashMap dex = cs.loadDict(16, k -\u003e k.readUint(16), v -\u003e CellSlice.beginParse(v).loadUint(16));\n\nlog.info(\"Deserialized hashmap from cell {}\", dex);\n```\n\nDeserialize HashMapE, that might be empty.\n\nNotice we use `loadDictE` here.\n\n```java\nTonHashMapE x = new TonHashMapE(9);\nx.elements.put(100L, Address.of(\"0QAljlSWOKaYCuXTx2OCr9P08y40SC2vw3UeM1hYnI3gDY7I\"));\n\nCell dictCell =\n    x.serialize(\n        k -\u003e CellBuilder.beginCell().storeUint((Long) k, 9).endCell().getBits(),\n        v -\u003e CellBuilder.beginCell().storeAddress((Address) v).endCell());\n\nCell cellWithDict = CellBuilder.beginCell().storeDict(dictCell).endCell();\n\nCellSlice cs = CellSlice.beginParse(cellWithDict);\nTonHashMapE dex =\n    cs.loadDictE(9, k -\u003e k.readUint(9), v -\u003e CellSlice.beginParse(v).loadAddress());\n\nlog.info(\"Deserialized hashmap from cell {}\", dex);\nassertThat(dex.elements.size()).isEqualTo(1);\n```\n\n### TLB Serialize Deserialize\n\nThe Type Language Binary (TL-B) for TON Blockchain is a domain-specific language designed to describe the structure of\ndata in the TON Blockchain.\nAll TL-B types defined in [schema](https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb).\n\nSpecial TL-B parsers can read schemes to deserialize binary data into different objects.\n\nton4j supports constructors and parsers of all TON TL-B types.\n\nFor example, if you know that BoC contains ValueFlow type, you can deserialize it in the following way\n\n```java\nCell c = CellBuilder.beginCell()\n        .fromBoc(\"b5ee9c72410106010054000211b8e48dfb4a0eebb0040105022581fa7454b05a2ea2ac0fd3a2a5d348d2954008020202012004030015bfffffffbcbd0efda563d00015be000003bcb355ab466ad0001d43b9aca00250775d8011954fc40008b63e6951\")\n        .endCell();\nlog.info(\"CellType {}\", c.getCellType());\nValueFlow valueFlow = ValueFlow.deserialize(CellSlice.beginParse(c));\nlog.info(\"valueFlow {}\", valueFlow);\nassertThat(valueFlow.getFeesCollected().getCoins()).isEqualTo(2700000000L);\nassertThat(valueFlow.getRecovered().getCoins()).isEqualTo(2700000000L);\nassertThat(valueFlow.getFeesImported().getCoins()).isEqualTo(1000000000L);\nassertThat(valueFlow.getFromPrevBlk().getCoins()).isEqualTo(new BigInteger(\"2280867924805872170\"));\n```\n\nThe next example shows how to create POJO, serialize it to Cell and deserialize back to a TL-B type Java object.\n\n```java\nAddress src = Address.of(\"EQAOp1zuKuX4zY6L9rEdSLam7J3gogIHhfRu_gH70u2MQnmd\");\nInternalMessageInfo internalMessageInfo =\n  InternalMessageInfo.builder()\n    .iHRDisabled(false)\n    .bounce(true)\n    .bounced(false)\n    .srcAddr(\n        MsgAddressIntStd.builder().workchainId(src.wc).address(src.toBigInteger()).build())\n    .dstAddr(\n      MsgAddressIntStd.builder()\n        .workchainId((byte) 2)\n        .address(BigInteger.valueOf(2))\n        .build())\n    .value(CurrencyCollection.builder().coins(Utils.toNano(0.5)).build())\n    .createdAt(5L)\n    .createdLt(BigInteger.valueOf(2))\n    .build();\n\nInternalMessageInfo loadedInternalMessageInfo = InternalMessageInfo.deserialize(CellSlice.beginParse(internalMessageInfo.toCell()));\n```\n\n## Emulators\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n  \u003cartifactId\u003eemulator\u003c/artifactId\u003e\n  \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nTON provides two types of Emulators: `Transaction` and `TVM`.\nBoth are used to quickly test behavior in an emulated environment.\n\nBoth emulators require tonlibjson shared library.\n\n### TVM Emulator\n\nTVM emulator allows you to replay `run_method`, `external` and `internal` message against account's `StateInit` (\ncode+data)\n\n#### Emulate run methods\n\n```java\nTonlib tonlib = Tonlib.builder().pathToTonlibSharedLib(Utils.getTonlibGithubUrl()).build();\n// create WalletV4R2\nWalletV4R2 walletV4R2 = WalletV4R2.builder().tonProvider(tonlib).keyPair(keyPair).walletId(42).build();\n\n// create TVM emulator\nTvmEmulator tvmEmulator =\n  TvmEmulator.builder()\n    .pathToEmulatorSharedLib(Utils.getEmulatorGithubUrl())\n    .codeBoc(walletV4R2.getStateInit().getCode())\n    .dataBoc(walletV4R2.getStateInit().getData())\n    .verbosityLevel(TvmVerbosityLevel.UNLIMITED)\n    .build();\n\n// execute method seqno against smart contract \nGetMethodResult methodResult = tvmEmulator.runGetMethod(Utils.calculateMethodId(\"seqno\"));\n// or use a shorter version\nGetMethodResult methodResult = tvmEmulator.runGetSeqNo();\n\n// emulator a call of a method with parameters\nString stackSerialized =\n  VmStack.builder()\n    .depth(0)\n    .stack(VmStackList.builder().tos(Collections.emptyList()).build())\n    .build()\n    .toCell()\n    .toBase64();\n\nGetMethodResult methodResult = tvmEmulator.runGetMethod(Utils.calculateMethodId(\"get_plugin_list\"), stackSerialized);\n```\n\n#### Emulate internal transaction\n\n```java\nCell body =\n    CellBuilder.beginCell()\n        .storeUint(0x706c7567, 32) // op request funds\n        .endCell();\n\nSendInternalMessageResult result = tvmEmulator.sendInternalMessage(body.toBase64(), Utils.toNano(0.11).longValue());\n\nlog.info(\"result sendInternalMessage, {}\", result);\n\nOutList actions = result.getActions();\nlog.info(\"compute phase actions {}\", actions);\n```\n\n#### Emulate external message\n\n```java\nWalletV4R2Config config =\n  WalletV4R2Config.builder()\n    .operation(0)\n    .walletId(42)\n    .seqno(0)\n    .destination(Address.of(\"0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d\"))\n    .amount(Utils.toNano(0.124))\n    .build();\n\nMessage msg = walletV4R2.prepareExternalMsg(config);\nSendExternalMessageResult result = tvmEmulator.sendExternalMessage(msg.getBody().toBase64());\nOutList actions = result.getActions();\nlog.info(\"compute phase actions {}\", actions);\n\n// send one more time\nconfig =  \n  WalletV4R2Config.builder()\n    .operation(0)\n    .walletId(42)\n    .seqno(1)\n    .destination(Address.of(\"0:258e549638a6980ae5d3c76382afd3f4f32e34482dafc3751e3358589c8de00d\"))\n    .amount(Utils.toNano(0.123))\n    .build();\n\nmsg = walletV4R2.prepareExternalMsg(config);\ntvmEmulator.sendExternalMessage(msg.getBody().toBase64());\n\nassertEquals(2, tvmEmulator.runGetSeqNo().longValue());\n```\n\n### Transaction Emulator\n\nThe main difference between TVM and Transaction emulators is that the latter one executes transactions\nagainst `ShardAccount` and proceeds additionally through the\nAction [phase](https://docs.ton.org/foundations/phases#execution-phases).\n\n```java\n// create a test account to simulate tx against\nAccount testAccount =\n    Account.builder()\n    .isNone(false)\n    .address(MsgAddressIntStd.of(\"-1:0000000000000000000000000000000000000000000000000000000000000000\"))\n    .storageInfo(StorageInfo.builder()\n      .storageUsed(StorageUsed.builder()\n      .cellsUsed(BigInteger.ZERO)\n      .bitsUsed(BigInteger.ZERO)\n      .build())\n    .storageExtraInfo(StorageExtraNone.builder().build())\n    .lastPaid(System.currentTimeMillis() / 1000)\n    .duePayment(BigInteger.ZERO)\n    .build())\n    .accountStorage(\n      AccountStorage.builder()\n        .balance(CurrencyCollection.builder().coins(Utils.toNano(2)) // initial balance\n        .build())\n      .accountState(AccountStateActive.builder()\n         .stateInit(StateInit.builder()\n          .code(CellBuilder.beginCell().fromBoc(\"b5ee9c7241010101004e000098ff0020dd2082014c97ba9730ed44d0d70b1fe0a4f260810200d71820d70b1fed44d0d31fd3ffd15112baf2a122f901541044f910f2a2f80001d31f31d307d4d101fb00a4c8cb1fcbffc9ed5470102286\")\n          .endCell())    \n          .build())\n      .build())\n      .accountStatus(\"ACTIVE\")\n      .build())\n    .build();\n\n// create a shard account to simulate against \nShardAccount shardAccount =\n    ShardAccount.builder()\n        .account(testAccount)\n        .lastTransHash(BigInteger.ZERO)\n        .lastTransLt(BigInteger.ZERO)\n        .build();\n\nString shardAccountBocBase64 = shardAccount.toCell().toBase64();\n\n// create an internal message to simulate \nMessage internalMsg =\n  Message.builder()\n    .info(\n      InternalMessageInfo.builder()\n        .srcAddr(\n          MsgAddressIntStd.builder()\n            .workchainId((byte) 0)\n            .address(BigInteger.ZERO)\n            .build())\n        .dstAddr(\n          MsgAddressIntStd.builder()\n            .workchainId((byte) 0)\n            .address(BigInteger.ZERO)\n            .build())\n        .value(CurrencyCollection.builder().coins(Utils.toNano(1)).build())\n        .bounce(false)\n        .createdAt(0)\n        .build())\n    .init(null)\n    .body(null)\n    .build();\n\nString internalMsgBocBase64 = internalMsg.toCell().toBase64();\n\n// simulate an internal message against the shard account \nEmulateTransactionResult result =  txEmulator.emulateTransaction(shardAccountBocBase64, internalMsgBocBase64);\nlog.info(\"result {}\", result);\nassertThat(result.isSuccess()).isTrue();\nlog.info(\"new shardAccount {}\", result.getNewShardAccount());\nlog.info(\"new transaction {}\", result.getTransaction());\nlog.info(\"new actions {}\", result.getActions());\n```\n\n## TON connect\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eorg.ton.ton4j\u003c/groupId\u003e\n  \u003cartifactId\u003etonconnect\u003c/artifactId\u003e\n  \u003cversion\u003e2.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nRead about the TON Connect and how it\nworks [here](https://docs.ton.org/develop/dapps/ton-connect/sign#how-does-it-work).\nBelow are step-by-step instructions how it works in `ton4j`.\n\n```java\n// prepare data for demonstration\nAdnlLiteClient client = AdnlLiteClient.builder().myLocalTon().build();\n\nbyte[] secretKey = Utils.hexToSignedBytes(\"1bd726fa69d850a5c0032334b16802c7eda48fde7a0e24f28011b22159cc97b7\");\nTweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(secretKey);\nlog.info(\"prvKey: {}\", Utils.bytesToHex(secretKey));\nlog.info(\"pubKey: {}\", Utils.bytesToHex(keyPair.getPublicKey()));\n\nString addressStr = \"0:1da77f0269bbbb76c862ea424b257df63bd1acb0d4eb681b68c9aadfbf553b93\";\nAddress address = Address.of(addressStr);\nAccount account = client.getAccount(address);\nlog.info(\"account {}\", account);\n\n// Step 1. User initiates a sign-in process at the dapp's frontend, then dapp sends a request to the backend\n// to generate a ton_proof payload\n\n// Step 2. Backend generates a TonProof entity and sends it to a frontend\n\nString payload = \"doc-example-\u003cBACKEND_AUTH_ID\u003e\";\nString sig = \"\";\n\nString proof = String.format(\n  \"{\\n\"\n      + \"                \\\"timestamp\\\": 1722999580, \\n\"\n      + \"                \\\"domain\\\": {\\n\"\n      + \"                    \\\"lengthBytes\\\": 16, \\n\"\n      + \"                    \\\"value\\\": \\\"xxx.xxx.com\\\"\\n\"\n      + \"                }, \\n\"\n      + \"                \\\"signature\\\": \\\"%s\\\", \\n\" + // \u003c---------- to be updated\n      \"                \\\"payload\\\": \\\"%s\\\"\\n\"\n      + \"            }\",\n  sig, payload);\n\nlog.info(\"proof: {}\", proof);\nTonProof tonProof = gson.fromJson(proof, TonProof.class);\nbyte[] message = TonConnect.createMessageForSigning(tonProof, addressStr);\n\n// Step 3. Frontend signs in to the wallet using TonProof and receives back a signed TonProof.\n// Basically a user signs the payload with his private key.\nbyte[] signature = Utils.signData(keyPair.getPublicKey(), secretKey, message);\nlog.info(\"signature: {}\", Utils.bytesToHex(signature));\n// update TonProof by adding a signature\ntonProof.setSignature(Utils.bytesToBase64SafeUrl(signature));\nlog.info(\"proof (updated): {}\", tonProof);\n\n// Step 4. Frontend sends signed TonProof to a backend for verification.\n// If a smart contract does not have a get_public_key method, you can calculate a public key from\n// its state init.\n\nStateInit stateInit =\n  StateInit.builder()\n    .code(account.getStateInit().getCode())\n    .data(account.getStateInit().getData())\n    .build();\n\nlog.info(\"wallet code bocHex: {}\", account.getStateInit().getCode().toHex());\nlog.info(\"wallet version {}\", WalletCodes.getKeyByValue(account.getStateInit().getCode().toHex()));\n\nBigInteger publicKeyRemote = client.getPublicKey(address);\n// OR handover stateInit to calculate pubkey from contract's data\n\nString accountString =\n  String.format(\n  \"{\\n\"\n          + \"      \\\"address\\\": \\\"%s\\\", \\n\"\n          + \"      \\\"chain\\\": \\\"-239\\\", \\n\"\n          + \"      \\\"walletStateInit\\\": \\\"%s\\\", \\n\" + // either this\n          \"        \\\"publicKey\\\": \\\"%s\\\"\\n\" +         // or this\n          \"    }\",\naddress.toRaw(), stateInit.toCell().toBase64(), publicKeyRemote.toString(16));\nlog.info(\"accountString: {}\", accountString);\n\nWalletAccount walletAccount = gson.fromJson(accountString, WalletAccount.class);\nlog.info(\"account:{}\", walletAccount);\n\n// Step 5. Backend verifies the proof\nassertThat(TonConnect.checkProof(tonProof, walletAccount)).isTrue();\n```\n\nA shorter example\n\n```java\nString addressStr = \"0:2d29bfa071c8c62fa3398b661a842e60f04cb8a915fb3e749ef7c6c41343e16c\";\n\n// backend prepares a payload and generates a TonProof\n\nTonProof tonProof =\n    TonProof.builder()\n        .timestamp(1722999580)\n        .domain(Domain.builder().value(\"xxx.xxx.com\").lengthBytes(16).build())\n        .payload(\"doc-example-\u003cBACKEND_AUTH_ID\u003e\")\n        .build();\n\n// user wallet signs it\nbyte[] secretKey =\n    Utils.hexToSignedBytes(\"F182111193F30D79D517F2339A1BA7C25FDF6C52142F0F2C1D960A1F1D65E1E4\");\nTweetNaclFast.Signature.KeyPair keyPair = TweetNaclFast.Signature.keyPair_fromSeed(secretKey);\nbyte[] message = TonConnect.createMessageForSigning(tonProof, addressStr);\nbyte[] signature = Utils.signData(keyPair.getPublicKey(), secretKey, message);\nlog.info(\"signature: {}\", Utils.bytesToHex(signature));\n\n// and updates TonProof by adding a signature\ntonProof.setSignature(Utils.bytesToBase64SafeUrl(signature));\n\n// backend verifies if proof is valid\nWalletAccount walletAccount =\n    WalletAccount.builder()\n        .chain(-239)\n        .address(addressStr)\n        .publicKey(\"82a0b2543d06fec0aac952e9ec738be56ab1b6027fc0c1aa817ae14b4d1ed2fb\")\n        .build();\n\nassertThat(TonConnect.checkProof(tonProof, walletAccount)).isTrue();\n```\n\n## Smart contract disassembler\n\nProvides Fift-like code from a smart contract compiled source.\n\nDecompile from Cell or BoC\n\n```java\n//Load Cell from BoC\nCell codeCell = Cell.fromBoc(code);\nString result = Disassembler.fromCode(codeCell);\n// or simply decompile directly from BoC\nString result = Disassembler.fromBoc(codeAsBoc);\n```\n\nGet account code by address and disassemble it\n\n```java\nTonlib tonlib = Tonlib.builder()\n    .testnet(false)\n    .pathToTonlibSharedLib(Utils.getTonlibGithubUrl())\n    .build();\n\nAddress address = Address.of(\"smart-contract-address\");\nFullAccountState accountState = tonlib.getAccountState(address);\nbyte[] accountStateCode = Utils.base64ToBytes(accountState.getAccount_state().getCode());\nString disassembledInstructions = Disassembler.fromBoc(accountStateCode);\n```\n\n## Notes\n\n- Testnet faucet only works on testnet. On the mainnet, top up the wallet address externally before deploying.\n- Prefer public-key-only flows and external signing when private keys must not be exposed.\n- More wallet and smart-contract examples live in `smartcontract/src/test/java/org/ton/ton4j/smartcontract`.\n\n## Features\n\n* ✅ BitString manipulations\n* ✅ Cells serialization / deserialization\n* ✅ TL-B serialization / deserialization\n* ✅ TL serialization / deserialization\n* ✅ Cell builder and cell slicer (reader)\n* ✅ Tonlib, Lite-client, TVM/TX, Fift, Func and Tolk wrappers\n* ✅ ADNL Lite-client\n* ✅ TON RocksDB direct access\n* ✅ TonConnect\n* ✅ TonCenter V2 wrapper\n* ✅ TonCenter Indexer V3 wrapper\n* ✅ Fift, Func, Tolk wrappers\n* ✅ BoC disassembler\n* ✅ Extra-currency support and examples\n* ✅ Support num, cell and slice as arguments for runMethod\n* ✅ Render List, Tuple, Slice, Cell and Number results from runMethod\n* ✅ Generate or import private key, sign, encrypt and decrypt using Tonlib\n* ✅ Encrypt/decrypt with mnemonic\n* ✅ Deploy contracts and send external messages using Tonlib\n* ✅ Wallets: Simple (V1), V2, V3, V4 (plugins), V5, Lockup, ~~Highload~~/Highload-V3, Highload-V3S (Secp256k1), DNS,\n  Jetton/Jetton V2, StableCoin, NFT,\n  Payment-channels, ~~Multisig V1~~, Multisig V2\n* ✅ HashMap, HashMapE, PfxHashMap, PfxHashMapE, HashMapAug, HashMapAugE serialization / deserialization\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=ton-blockchain/ton4j\u0026type=Date)](https://www.star-history.com/#ton-blockchain/ton4j\u0026Date)\n\n\u003c!-- Badges --\u003e\n\n[maven-central-svg]: https://img.shields.io/maven-central/v/org.ton.ton4j/smartcontract\n\n[maven-central]: https://mvnrepository.com/artifact/org.ton.ton4j/smartcontract\n\n[jitpack-svg]: https://jitpack.io/v/ton-blockchain/ton4j.svg\n\n[jitpack]: https://jitpack.io/#ton-blockchain/ton4j\n\n[ton-svg]: https://img.shields.io/badge/Based%20on-TON-blue\n\n[ton]: https://ton.org\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fton-blockchain%2Fton4j","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fton-blockchain%2Fton4j","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fton-blockchain%2Fton4j/lists"}