{"id":13410115,"url":"https://github.com/xssnick/tonutils-go","last_synced_at":"2026-05-26T13:07:01.086Z","repository":{"id":37003330,"uuid":"485893520","full_name":"xssnick/tonutils-go","owner":"xssnick","description":"TON SDK Library in pure Golang for interacting with The Open Network ecosystem using native protocols, such as ADNL, RLDP and etc. ","archived":false,"fork":false,"pushed_at":"2026-05-11T11:59:48.000Z","size":9455,"stargazers_count":688,"open_issues_count":48,"forks_count":190,"subscribers_count":19,"default_branch":"master","last_synced_at":"2026-05-11T12:40:24.046Z","etag":null,"topics":["blockchain","golang","golang-library","sdk","sdk-go","telegram","ton","toncoin"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xssnick.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":null,"dco":null,"cla":null}},"created_at":"2022-04-26T17:56:45.000Z","updated_at":"2026-05-07T19:01:52.000Z","dependencies_parsed_at":"2023-07-13T05:28:02.221Z","dependency_job_id":"f944548c-d76e-4a32-8c85-103c1605e021","html_url":"https://github.com/xssnick/tonutils-go","commit_stats":null,"previous_names":["xssnick/tonutils"],"tags_count":91,"template":false,"template_full_name":null,"purl":"pkg:github/xssnick/tonutils-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xssnick%2Ftonutils-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xssnick%2Ftonutils-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xssnick%2Ftonutils-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xssnick%2Ftonutils-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xssnick","download_url":"https://codeload.github.com/xssnick/tonutils-go/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xssnick%2Ftonutils-go/sbom","scorecard":{"id":1236679,"data":{"date":"2025-08-25","repo":{"name":"github.com/xssnick/tonutils-go","commit":"167b5d35ef9de1b4403498b6ccc0c47823c84ae6"},"scorecard":{"version":"v5.2.1-41-g40576783","commit":"40576783fda6698350fcbbeaea760ff827433034"},"score":5,"checks":[{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/go.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":2,"reason":"Found 1/4 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#code-review"}},{"name":"Maintained","score":10,"reason":"30 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#cii-best-practices"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/xssnick/tonutils-go/go.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/xssnick/tonutils-go/go.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/go.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/xssnick/tonutils-go/go.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/go.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/xssnick/tonutils-go/go.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/go.yml:46: update your workflow using https://app.stepsecurity.io/secureworkflow/xssnick/tonutils-go/go.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/go.yml:61: update your workflow using https://app.stepsecurity.io/secureworkflow/xssnick/tonutils-go/go.yml/master?enable=pin","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/40576783fda6698350fcbbeaea760ff827433034/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-09-01T13:25:39.462Z","repository_id":37003330,"created_at":"2025-09-01T13:25:39.462Z","updated_at":"2025-09-01T13:25:39.462Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33521449,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T03:12:49.672Z","status":"ssl_error","status_checked_at":"2026-05-26T03:12:47.976Z","response_time":63,"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","golang","golang-library","sdk","sdk-go","telegram","ton","toncoin"],"created_at":"2024-07-30T20:01:05.050Z","updated_at":"2026-05-26T13:07:01.079Z","avatar_url":"https://github.com/xssnick.png","language":"Go","funding_links":[],"categories":["🧑‍💻 Development"],"sub_categories":["Libraries \u0026 SDKs"],"readme":"# tonutils-go\n\n\u003cimg align=\"right\" width=\"425px\" src=\"https://github.com/xssnick/props/blob/master/logoimg.png?raw=true\"\u003e\n\n[![Based on TON][ton-svg]][ton]\n[![Telegram Channel][tgc-svg]][tg-channel]\n![Coverage](https://img.shields.io/badge/Coverage-74.0%25-brightgreen)\n\nGolang library for interacting with TON blockchain.\n\nThis library is native golang implementation of ADNL and lite protocol. It works as connection pool and can be connected to multiple lite servers in the same time, balancing is done on lib side.\n\nIt is concurrent safe and can be used from multiple goroutines under high workloads.\n\nAll main TON protocols are implemented: ADNL, DHT, RLDP, Overlays, etc.\n\n------\n\nIf you love this library and want to support its development you can donate any amount of coins to this ton address ☺️\n`EQBx6tZZWa2Tbv6BvgcvegoOQxkRrVaBVwBOoW85nbP37_Go`\n\nYou can find many usage examples in **[example](https://github.com/xssnick/tonutils-go/tree/master/example)** directory\n\n### How to use\n- [Connection](#Connection)\n- [Wallet](#Wallet)\n  - [Example](https://github.com/xssnick/tonutils-go/blob/master/example/wallet/main.go)\n  - [Create](#Wallet)\n  - [Transfer](#Wallet)\n  - [Balance](#Wallet)\n  - [Transfer to many](https://github.com/xssnick/tonutils-go/blob/master/example/highload-wallet/main.go)\n  - [Send message to contract](https://github.com/xssnick/tonutils-go/blob/master/example/send-to-contract/main.go)\n  - [Build transaction and send from other place](https://github.com/xssnick/tonutils-go/blob/master/example/wallet-cold-alike/main.go#L61)\n- [Accounts](#Account-info-and-transactions)\n  - [List transactions](#Account-info-and-transactions)\n  - [Get balance](https://github.com/xssnick/tonutils-go/blob/master/example/account-state/main.go)\n  - [Subscribe on transactions](https://github.com/xssnick/tonutils-go/blob/master/example/accept-payments/main.go)\n- [NFT](#NFT)\n  - [Details](#NFT)\n  - [Mint](https://github.com/xssnick/tonutils-go/blob/master/example/nft-mint/main.go#L42)\n  - [Transfer](https://github.com/xssnick/tonutils-go/blob/master/ton/nft/integration_test.go#L89)\n- [Jettons](#Jettons)\n  - [Details](#Jettons)\n  - [Transfer](https://github.com/xssnick/tonutils-go/blob/master/example/jetton-transfer/main.go)\n- [DNS](#DNS)\n  - [Resolve](#DNS)\n  - [Get records](#Records)\n  - [Set records](#Records)\n- [Contracts](#Contracts)\n  - [Use get methods](#Using-GET-methods)\n  - [Send external message](#Send-external-message)\n  - [Deploy](#Deploy)\n- [Cells](#Cells)\n  - [Create](#Cells)\n  - [Parse](#Cells)\n  - [Dictionary](#Dictionary)\n  - [TLB Loader/Serializer](#TLB-Loader)\n  - [BoC](#BoC)\n  - [Proof creation](#Proofs)\n  - [MerkleProofBuilder](#MerkleProofBuilder)\n- [Network](https://github.com/xssnick/tonutils-go/tree/master/adnl)\n  - [ADNL UDP](https://github.com/xssnick/tonutils-go/blob/master/adnl/adnl_test.go)\n- [Custom reconnect policy](#Custom-reconnect-policy)\n- [Features to implement](#Features-to-implement)\n\nYou could also join our **[Telegram channel](https://t.me/tonutilsnews)** and **[group](https://t.me/tonutils)**, feel free ask any questions :)\n\n### Connection\nYou can use liteservers from TON configs:\n* Mainnet public servers - `https://ton-blockchain.github.io/global.config.json`\n* Testnet public servers - `https://ton-blockchain.github.io/testnet-global.config.json`\n\nfrom liteservers section, you need to convert int to ip and take port and key.\n\nOr you can run your own full node, see TON docs.\n\nYou can connect like that:\n```golang\nclient := liteclient.NewConnectionPool()\n\nconfigUrl := \"https://ton-blockchain.github.io/testnet-global.config.json\"\nerr := client.AddConnectionsFromConfigUrl(context.Background(), configUrl)\nif err != nil {\n    panic(err)\n}\napi := ton.NewAPIClient(client).WithRetryTimeout(0, 5*time.Second) // automatic retries with failover and a per-attempt timeout\n```\n\nSince `client` implements connection pool, it can be the chance that some block is not yet applied on one of the nodes, so it can lead to errors.\nIf you want to bound all requests of operation to single node, use \n```go\nctx := client.StickyContext(context.Background())\n```\nAnd pass this context to methods.\n\n### Wallet\nYou can use existing wallet or generate new one using `wallet.NewSeed()`, wallet will be initialized by the first message sent from it. This library will deploy and initialize wallet contract if it is not initialized yet. \n\nYou can also send any message to any contract using `w.Send` method, it accepts `tlb.InternalMessage` structure, you can dive into `w.Transfer` implementation and see how it works.\n\nExample of basic usage:\n```golang\nwords := strings.Split(\"birth pattern ...\", \" \")\n\nw, err := wallet.FromSeedWithOptions(api, words, wallet.V3)\nif err != nil {\n    panic(err)\n}\n\nblock, err := api.CurrentMasterchainInfo(context.Background())\nif err != nil {\n    panic(err)\n}\n\nbalance, err := w.GetBalance(context.Background(), block)\nif err != nil {\n    panic(err)\n}\n\nif balance.Nano().Uint64() \u003e= 3000000 {\n    addr := address.MustParseAddr(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\")\n    err = w.Transfer(context.Background(), addr, tlb.MustFromTON(\"0.003\"), \"Hey bro, happy birthday!\")\n    if err != nil {\n        panic(err)\n    }\n}\n```\nYou can find full working example at `example/wallet/main.go`\n### Contracts \nHere is the description of features which allow us to trigger contract's methods\n\n#### Using GET methods\nLet's imagine that we have contract with method\n```func\ncell mult(int a, int b) method_id {\n  return begin_cell().store_uint(a * b, 64).end_cell();\n}\n```\n\nWe can trigger it and get result this way:\n```golang\n// api = initialized ton.APIClient, see Connection in readme\n\n// we need fresh block info to run get methods\nblock, err := api.CurrentMasterchainInfo(context.Background())\nif err != nil {\n    panic(err)\n}\n\n// contract address\naddr := address.MustParseAddr(\"kQB3P0cDOtkFDdxB77YX-F2DGkrIszmZkmyauMnsP1gg0inM\")\n\n// run get method `mult` of contract with int arguments 7 and 8\nres, err := api.RunGetMethod(context.Background(), block, addr, \"mult\", 7, 8)\nif err != nil {\n    // if contract exit code != 0 it will be treated as an error too\n    panic(err)\n}\n\n// we are sure that return value is 1 cell, we can directly cast it and parse\nslice, err := res.MustCell(0).BeginParse()\nif err != nil {\n    panic(err)\n}\nval, err := slice.LoadUInt(64)\nif err != nil {\n    panic(err)\n}\n\n// prints 56\nprintln(val)\n```\n\n#### Send external message\nUsing messages, you can interact with contracts to modify state. For example, it can be used to interact with wallet and send transactions to others.\n\nYou can send message to contract like that:\n```golang\n// message body\ndata := cell.BeginCell().\n    MustStoreUInt(777, 64).\n    EndCell()\n\n// contract address\naddr := address.MustParseAddr(\"kQBkh8dcas3_OB0uyFEDdVBBSpAWNEgdQ66OYF76N4cDXAFQ\")\n\nmsg := \u0026tlb.ExternalMessage{\n    DstAddr: addr,\n    Body:    data,\n}\n\n// send external message, processing fees will be taken from contract\nif err := api.SendExternalMessage(context.Background(), msg); err != nil {\n    panic(err)\n}\n```\nYou can find full working example at `example/external-message/main.go`\n\n#### Deploy\nContracts can be deployed using wallet's method `DeployContract`, \nyou should pass 3 cells there: contract code, contract initial data, message body.\n\nYou can find example [here](https://github.com/xssnick/tonutils-go/blob/master/example/deploy-nft-collection/main.go)\n\n### Account info and transactions\nYou can get full account information including balance, stored data and even code using GetAccount method. \nYou can also get account's list of transactions with all details.\n\nExample:\n```golang\n// TON Foundation account\naddr := address.MustParseAddr(\"EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N\")\n\nb, err := api.CurrentMasterchainInfo(context.Background())\nif err != nil {\n    log.Fatalln(\"get block err:\", err.Error())\n    return\n}\n\naccount, err := api.GetAccount(context.Background(), b, addr)\nif err != nil {\n    log.Fatalln(\"get account err:\", err.Error())\n    return\n}\n\n// Balance: ACTIVE\nfmt.Printf(\"Status: %s\\n\", account.State.Status)\n// Balance: 66559946.09 TON\nfmt.Printf(\"Balance: %s TON\\n\", account.State.Balance.String())\nif account.Data != nil { // Can be nil if account is not active\n    // Data: [0000003829a9a31772c9ed6b62a6e2eba14a93b90462e7a367777beb8a38fb15b9f33844d22ce2ff]\n    fmt.Printf(\"Data: %s\\n\", account.Data.Dump())\n}\n\n// load last 15 transactions\nlist, err := api.ListTransactions(context.Background(), addr, 15, account.LastTxLT, account.LastTxHash)\nif err != nil {\n    // In some cases you can get error:\n    // lite server error, code XXX: cannot compute block with specified transaction: lt not in db\n    // it means that current lite server does not store older data, you can query one with full history\n    log.Printf(\"send err: %s\", err.Error())\n    return\n}\n\n// oldest = first in list\nfor _, t := range list {\n    // Out: 620.9939549 TON, To [EQCtiv7PrMJImWiF2L5oJCgPnzp-VML2CAt5cbn1VsKAxLiE]\n    // In: 494.521721 TON, From EQB5lISMH8vLxXpqWph7ZutCS4tU4QdZtrUUpmtgDCsO73JR \n    // ....\n    fmt.Println(t.String())\n}\n```\nYou can find extended working example at `example/account-state/main.go`\n\n### TLB Loader\nYou can load cells directly into Go structs using TLB tags and serialize them back using the same struct definition.\n\nFor most application-level code it is recommended to use TLB structs instead of manual raw cell assembly.\nRaw `cell.BeginCell()` / `Load*` flows are still useful for low-level work, debugging, uncommon layouts and dynamic structures,\nbut if payload layout is known in advance, `tlb.Parse` (or `tlb.LoadFromCell` when you already have a `*cell.Slice`) and `tlb.ToCell` are usually simpler, shorter and less error-prone.\n\nSupported tags:\n\n- `tlb:\"-\"` - skip field completely\n- `tlb:\"#deadbeef\"` - exact hex magic / constructor prefix for `_ tlb.Magic`\n- `tlb:\"$1101\"` - exact binary magic / constructor prefix for `_ tlb.Magic`\n- `tlb:\"## N\"` - fixed-width integer in `N` bits. For small widths regular Go integer types can be used, for large widths use `*big.Int`\n- `tlb:\"bits N\"` - exactly `N` bits into/from `[]byte`\n- `tlb:\"bool\"` - one-bit boolean\n- `tlb:\"addr\"` - TON address, usually `*address.Address`\n- `tlb:\".\"` - nested struct stored in the current cell\n- `tlb:\"^\"` - nested value stored in a referenced cell. If the field type is `*cell.Cell`, raw referenced cell is returned without nested parsing\n- `tlb:\"maybe \u003ctag\u003e\"` - one presence bit followed by nested value only when present. Common examples: `maybe ^`, `maybe .`\n- `tlb:\"either X Y\"` - one selector bit: `0` means parse/store as `X`, `1` means parse/store as `Y`. During serialization it tries `X` first, then `Y`\n- `tlb:\"either leave {bits},{refs} X Y\"` - same as `either`, but chosen branch must still leave the requested number of free bits and refs in the current builder after serialization\n- `tlb:\"dict N\"` - `HashmapE` dictionary with `N`-bit keys\n- `tlb:\"dict inline N\"` - inline `Hashmap` dictionary with `N`-bit keys\n- `tlb:\"?FieldName \u003ctag\u003e\"` - conditional field. It is loaded/stored only when previously declared boolean field `FieldName` is `true`\n- `tlb:\"[TypeA,TypeB,...]\"` - interface/union field resolved by registered magic. Can be combined with other tags, for example `^ [ShardStateUnsplit,ShardStateSplit]`\n\nTags can be combined. Typical examples:\n\n- `tlb:\"maybe ^\"` - optional reference\n- `tlb:\"maybe .\"` - optional inline nested struct\n- `tlb:\"?HasValue maybe ^\"` - conditional optional reference\n- `tlb:\"^ [TypeA,TypeB]\"` - referenced union selected by magic\n- `tlb:\"dict inline 256\"` - inline dictionary with 256-bit keys\n\nCustom parsing/serialization hooks are also supported:\n\n- if a value implements `tlb.Unmarshaler`, its `LoadFromCell` method is used by `tlb.Parse` and `tlb.LoadFromCell`\n- if a value implements `tlb.Marshaller`, `ToCell` calls its custom serializer\n\nFor exact behavior and edge cases, see comments on `tlb.Parse`, `tlb.LoadFromCell` and `tlb.ToCell`.\n\nExample of parsing:\n```golang\ntype ShardState struct {\n    _               tlb.Magic  `tlb:\"#9023afe2\"`\n    GlobalID        int32      `tlb:\"## 32\"`\n    ShardIdent      ShardIdent `tlb:\".\"`\n    Seqno           uint32     `tlb:\"## 32\"`\n    OutMsgQueueInfo *cell.Cell `tlb:\"^\"`\n    Accounts        struct {\n        ShardAccounts *cell.Dictionary `tlb:\"dict 256\"`\n    } `tlb:\"^\"`\n}\n\ntype ShardIdent struct {\n    PrefixBits  int8   `tlb:\"## 6\"`\n    WorkchainID int32  `tlb:\"## 32\"`\n    ShardPrefix uint64 `tlb:\"## 64\"`\n}\n\nvar state ShardState\nif err := tlb.Parse(\u0026state, cl); err != nil {\n    panic(err)\n}\n\nfmt.Println(\"global id:\", state.GlobalID)\nfmt.Println(\"seqno:\", state.Seqno)\nfmt.Println(\"accounts dict empty:\", state.Accounts.ShardAccounts.IsEmpty())\n```\n\nExample of parsing your own payload:\n```golang\ntype ExamplePayload struct {\n    _       tlb.Magic  `tlb:\"#a1b2c3d4\"`\n    QueryID uint64     `tlb:\"## 64\"`\n    Flags   uint8      `tlb:\"## 8\"`\n    Body    *cell.Cell `tlb:\"^\"`\n}\n\npayloadCell := cell.BeginCell().\n    MustStoreUInt(0xa1b2c3d4, 32).\n    MustStoreUInt(123, 64).\n    MustStoreUInt(7, 8).\n    MustStoreRef(\n        cell.BeginCell().\n            MustStoreUInt(0xCAFE, 16).\n            EndCell(),\n    ).\n    EndCell()\n\nvar payload ExamplePayload\nif err := tlb.Parse(\u0026payload, payloadCell); err != nil {\n    panic(err)\n}\n\nfmt.Println(payload.QueryID)                  // 123\nfmt.Println(payload.Flags)                    // 7\nbody, err := payload.Body.BeginParse()\nif err != nil {\n    panic(err)\n}\nfmt.Println(body.MustLoadUInt(16)) // 0xCAFE\n```\n\n### TLB Serialize\nYou can serialize the same structs back into cells using `tlb.ToCell`.\n\n```golang\ntype ExamplePayload struct {\n    _       tlb.Magic  `tlb:\"#a1b2c3d4\"`\n    QueryID uint64     `tlb:\"## 64\"`\n    Flags   uint8      `tlb:\"## 8\"`\n    Body    *cell.Cell `tlb:\"^\"`\n}\n\npayload := ExamplePayload{\n    QueryID: 123,\n    Flags:   7,\n    Body: cell.BeginCell().\n        MustStoreUInt(0xCAFE, 16).\n        EndCell(),\n}\n\npayloadCell, err := tlb.ToCell(payload)\nif err != nil {\n    panic(err)\n}\n\nfmt.Println(payloadCell.Dump())\n```\n\nRoundtrip example:\n```golang\npayloadCell, err := tlb.ToCell(payload)\nif err != nil {\n    panic(err)\n}\n\nvar decoded ExamplePayload\nif err = tlb.Parse(\u0026decoded, payloadCell); err != nil {\n    panic(err)\n}\n\nfmt.Println(decoded.QueryID) // 123\n```\n\nSee also [build NFT mint message](https://github.com/xssnick/tonutils-go/blob/master/ton/nft/collection.go#L189) for a real-world serializer example.\n\n### NFT\nYou can mint, transfer, and get NFT information using `nft.ItemClient` and `nft.CollectionClient`, like that:\n```golang\napi := ton.NewAPIClient(client)\n\nnftAddr := address.MustParseAddr(\"EQDuPc-3EoqH72Gd6M45vmFsktQ8AzqaN14mweJhCjxg0d_b\")\nitem := nft.NewItemClient(api, nftAddr)\n\nnftData, err := item.GetNFTData(context.Background())\nif err != nil {\n    panic(err)\n}\n\n// get info about our nft's collection\ncollection := nft.NewCollectionClient(api, nftData.CollectionAddress)\ncollectionData, err := collection.GetCollectionData(context.Background())\nif err != nil {\n    panic(err)\n}\n\nfmt.Println(\"Collection addr      :\", nftData.CollectionAddress.String())\nfmt.Println(\"    content          :\", collectionData.Content.(*nft.ContentOffchain).URI)\nfmt.Println(\"    owner            :\", collectionData.OwnerAddress.String())\nfmt.Println(\"    minted items num :\", collectionData.NextItemIndex)\nfmt.Println()\nfmt.Println(\"NFT addr         :\", nftAddr.String())\nfmt.Println(\"    initialized  :\", nftData.Initialized)\nfmt.Println(\"    owner        :\", nftData.OwnerAddress.String())\nfmt.Println(\"    index        :\", nftData.Index)\n\nif nftData.Initialized {\n    // get full nft's content url using collection method that will merge base url with nft's data\n    nftContent, err := collection.GetNFTContent(context.Background(), nftData.Index, nftData.Content)\n    if err != nil {\n        panic(err)\n    }\n    fmt.Println(\"    part content :\", nftData.Content.(*nft.ContentOffchain).URI)\n    fmt.Println(\"    full content :\", nftContent.(*nft.ContentOffchain).URI)\n} else {\n    fmt.Println(\"    empty content\")\n}\n```\nYou can find full examples at `example/nft-info/main.go` and `example/nft-mint/main.go`\n\n### Jettons\nYou can get information about jetton, get jetton wallet and its balance, transfer jettons, and burn them using `jetton.Client` like that:\n```golang\n// jetton contract address\ncontract := address.MustParseAddr(\"EQAbMQzuuGiCne0R7QEj9nrXsjM7gNjeVmrlBZouyC-SCLlO\")\nmaster := jetton.NewJettonMasterClient(api, contract)\n\n// get information about jetton\ndata, err := master.GetJettonData(context.Background())\nif err != nil {\n    log.Fatal(err)\n}\n\nlog.Println(\"total supply:\", data.TotalSupply.Uint64())\n\n// get jetton wallet for account\nownerAddr := address.MustParseAddr(\"EQC9bWZd29foipyPOGWlVNVCQzpGAjvi1rGWF7EbNcSVClpA\")\njettonWallet, err := master.GetJettonWallet(context.Background(), ownerAddr)\nif err != nil {\n    log.Fatal(err)\n}\n\njettonBalance, err := jettonWallet.GetBalance(context.Background())\nif err != nil {\n    log.Fatal(err)\n}\nlog.Println(\"balance:\", jettonBalance.String())\n```\nYou can find full example, which also contains transfer, at `example/jettons/main.go`\n\n### DNS\nYou can get information about domains, get connected wallet and any other records, transfer domain, edit and do any other nft compatible operations using `dns.Client` like that:\n```golang\nroot, err := dns.GetRootContractAddr(context.Background(), api)\nif err != nil {\n    panic(err)\n}\n\nresolver := dns.NewDNSClient(api, root)\n\ndomain, err := resolver.Resolve(context.Background(), \"alice.ton\")\nif err != nil {\n    panic(err)\n}\n\nlog.Println(\"domain points to wallet address:\", domain.GetWalletRecord())\n```\nYou can find full example at `example/dns/main.go`\n\n##### Records\n\nYou could get any record of the domain using `domain.GetRecord(\"record name\")` method, it will return cell that will contain data structure depends on record type. \nAlternatively you can also use `domain.GetWalletRecord()` and `domain.GetSiteRecord()`, they will return already parsed data, like address for wallet, or slice of bytes with type for site.\n\nTo set domain records you can use `domain.BuildSetRecordPayload(\"record name\", dataCell)`, or predefined `BuildSetSiteRecordPayload(adnlAddress)`, `BuildSetWalletRecordPayload(walletAddress)`.\nIt will generate body cell that you need to send to domain contract from the owner's wallet.\n\nExample:\n```golang\n// get root dns address from network config\nroot, err := dns.GetRootContractAddr(ctx, api)\nif err != nil {\n    panic(err)\n}\n\nresolver := dns.NewDNSClient(api, root)\ndomainInfo, err := resolver.Resolve(ctx, \"utils.ton\")\nif err != nil {\n    panic(err)\n}\n\n// prepare transaction payload cell which will change site address record\nbody := domainInfo.BuildSetSiteRecordPayload(adnlAddr, false)\n\n// w = wallet initialized from domain owner seed phrase\nerr = w.Send(context.Background(), \u0026wallet.Message{\n  Mode: 1, // pay fees separately (from balance, not from amount)\n  InternalMessage: \u0026tlb.InternalMessage{\n    Bounce:  true, // return amount in case of processing error\n    DstAddr: domainInfo.GetNFTAddress(), // destination is domain contract\n    Amount:  tlb.MustFromTON(\"0.03\"),\n    Body:    body,\n  },\n}, true)\nif err != nil {\n    panic(err)\n}\n\n// done! now record of your site is changed!\n```\n\n### Cells\nWork with cells is very similar to FunC cells:\n```golang\nbuilder := cell.BeginCell().MustStoreUInt(0b10, 2).\n    MustStoreUInt(0b00, 2). // src addr_none\n    MustStoreAddr(addr).    // dst addr\n    MustStoreCoins(0)       // import fee 0\n\nbuilder.MustStoreUInt(0b11, 2). // has state init as cell\n    MustStoreRef(cell.BeginCell().\n        MustStoreUInt(0b00, 2).                     // no split depth, no special\n        MustStoreUInt(1, 1).MustStoreRef(code).     // with code\n        MustStoreUInt(1, 1).MustStoreRef(initData). // with data\n        MustStoreUInt(0, 1).                        // no libs\n    EndCell()).\n    MustStoreUInt(0, 1). // slice data\n    MustStoreUInt(0, 1)  // 1 bit as body, cause its required\n\nresult := builder.EndCell()\n\n// {bits_size}[{hex_data}]\n//  279[8800b18cc741b244e114685e1a9e9dc835bff5c157a32a38df49e87b71d0f0d29ba418] -\u003e {\n//    5[30] -\u003e {\n//      0[],\n//      8[01]\n//    }\n//  }\n\nfmt.Println(result.Dump())\n```\n\nLoad from cell:\n```golang\nslice, err := someCell.BeginParse()\nif err != nil {\n    panic(err)\n}\nwc := slice.MustLoadUInt(8)\ndata := slice.MustLoadSlice(256)\n```\nThere are 2 types of methods `Must` and regular. The difference is that in case of error, `Must` will panic, \nbut regular will just return error, so use `Must` only when you are sure that your data fits max cell size and other conditions\n\nTo debug cells you can use `Dump()` and `DumpBits()` methods of cell, they will return string with beautifully formatted cells and their refs tree\n\n##### Dictionary\n\nDictionary values are stored as ordinary cells, so in most cases you work with them through `LoadValue` and then parse the returned slice.\n\n```golang\ndict := cell.NewDict(32)\n\nkey := cell.BeginCell().MustStoreUInt(7, 32).EndCell()\nvalue := cell.BeginCell().\n    MustStoreUInt(0xAB, 8).\n    MustStoreRef(\n        cell.BeginCell().\n            MustStoreUInt(0xCDEF, 16).\n            EndCell(),\n    ).\n    EndCell()\n\nif err := dict.Set(key, value); err != nil {\n    panic(err)\n}\n\nloaded, err := dict.LoadValue(key)\nif err != nil {\n    panic(err)\n}\n\nfirstByte := loaded.MustLoadUInt(8)\nchild, err := loaded.LoadRef()\nif err != nil {\n    panic(err)\n}\n\nfmt.Println(firstByte)                     // 171\nfmt.Println(child.MustLoadUInt(16))       // 52719\n```\n\nIf you need to iterate over all values, use `LoadAll`:\n\n```golang\nitems, err := dict.LoadAll()\nif err != nil {\n    panic(err)\n}\n\nfor _, item := range items {\n    keyCell, err := item.Key.ToCell()\n    if err != nil {\n        panic(err)\n    }\n    valueCell, err := item.Value.ToCell()\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Println(\"key:\", keyCell.DumpBits())\n    fmt.Println(\"value:\", valueCell.Dump())\n}\n```\n##### BoC\n\nSometimes it is needed to import or export cell, for example to transfer over the network, for this, Bag of Cells serialization format is exists.\n\nYou can simply export cell using `ToBOC()` method of cell, and import it using `cell.FromBOC(bytes)`.\n\n[Example of use can be found in tests](https://github.com/xssnick/tonutils-go/blob/master/tvm/cell/cell_test.go#L76) or in [transfer-url-for-qr](https://github.com/xssnick/tonutils-go/blob/master/example/transfer-url-for-qr/main.go) example\n\n##### Proofs\n\nThere are 2 ways to create proofs:\n\n1. low-level `ProofSkeleton`, when you know exact refs you want to keep\n2. recommended `MerkleProofBuilder`, when proof should follow real loaded cells\n\nLow-level skeleton example:\n```golang\nsk := cell.CreateProofSkeleton()\nsk.ProofRef(0).ProofRef(1)\n\n// Tips:\n//   you could also do SetRecursive() on needed ref to add all its child cells to proof\n//   you can merge 2 proof skeletons using Merge\n\nmerkleProof, err := someCell.CreateProof(sk)\nif err != nil {\n    t.Fatal(err)\n}\n\nfmt.Println(merkleProof.Dump())\n```\n\nTo check proof you could use `cell.CheckProof(merkleProof, hash)` method, or `cell.UnwrapProof(merkleProof, hash)` if you want to continue to read proof body.\n\n##### MerkleProofBuilder\n\n`MerkleProofBuilder` is the easiest way to build proof for data you actually loaded from a dictionary, slice or nested structure.\n\n```golang\ndict := cell.NewDict(32)\n\nkey := cell.BeginCell().MustStoreUInt(7, 32).EndCell()\nvalue := cell.BeginCell().\n    MustStoreUInt(0xAB, 8).\n    MustStoreRef(\n        cell.BeginCell().\n            MustStoreUInt(0xCDEF, 16).\n            EndCell(),\n    ).\n    EndCell()\n\nif err := dict.Set(key, value); err != nil {\n    panic(err)\n}\n\nroot := dict.AsCell()\nproofBuilder := cell.NewMerkleProofBuilder(root)\nobserved := proofBuilder.Root().AsDict(32)\n\nloaded, err := observed.LoadValue(key)\nif err != nil {\n    panic(err)\n}\n\n// LoadValue marks the dictionary path and the terminal cell with the value as used.\n// LoadRef calls BeginParse on the child ref, so this ref will also stay ordinary in proof.\n_, err = loaded.LoadRef()\nif err != nil {\n    panic(err)\n}\n\nproof, err := proofBuilder.CreateProof()\nif err != nil {\n    panic(err)\n}\n\nproofBody, err := cell.UnwrapProof(proof, root.Hash())\nif err != nil {\n    panic(err)\n}\n\nloadedFromProof, err := proofBody.AsDict(32).LoadValue(key)\nif err != nil {\n    panic(err)\n}\n\nfmt.Println(loadedFromProof.MustLoadUInt(8)) // 171\n\nchild, err := loadedFromProof.LoadRef()\nif err != nil {\n    panic(err)\n}\n\nfmt.Println(child.MustLoadUInt(16)) // 52719\n```\n\nIf your value contains nested dictionary, tracing continues automatically through `LoadDict`:\n\n```golang\nproofBuilder := cell.NewMerkleProofBuilder(outerRoot)\nouterDict := proofBuilder.Root().AsDict(16)\n\nouterValue, err := outerDict.LoadValue(outerKey)\nif err != nil {\n    panic(err)\n}\n\ninnerDict, err := outerValue.LoadDict(16)\nif err != nil {\n    panic(err)\n}\n\ninnerValue, err := innerDict.LoadValue(innerKey)\nif err != nil {\n    panic(err)\n}\n\n// LoadValue already keeps the terminal cell with the value.\n// If the value has referenced child cells that should stay readable, parse those refs too.\nvalueRef, err := innerValue.LoadRef()\nif err != nil {\n    panic(err)\n}\n\nif err := valueRef.SkipBits(8); err != nil {\n    panic(err)\n}\n\nproof, err := proofBuilder.CreateProof()\nif err != nil {\n    panic(err)\n}\n```\n\nIf the nested dictionary is stored as a referenced cell, load that ref from the traced value and continue from it:\n\n```golang\nproofBuilder := cell.NewMerkleProofBuilder(root)\nobserved := proofBuilder.Root().AsDict(16)\n\nvalue, err := observed.LoadValue(key)\nif err != nil {\n    panic(err)\n}\n\nrefRoot, err := value.LoadRef()\nif err != nil {\n    panic(err)\n}\n\nsubdict, err := refRoot.ToDict(16)\nif err != nil {\n    panic(err)\n}\n\nsubval, err := subdict.LoadValue(subkey)\nif err != nil {\n    panic(err)\n}\n\n// Load referenced cells if they should not be replaced by pruned branches.\nsubref, err := subval.LoadRef()\nif err != nil {\n    panic(err)\n}\n\nif err := subref.SkipBits(8); err != nil {\n    panic(err)\n}\n\nproof, err := proofBuilder.CreateProof()\nif err != nil {\n    panic(err)\n}\n```\n\nThe builder keeps the cells that were actually loaded through the traced root.\nUnloaded branches are pruned automatically.\n\n### Custom reconnect policy\nBy default, standard reconnect method will be used - `c.DefaultReconnect(3*time.Second, 3)` which will do 3 tries and wait 3 seconds after each.\n\nBut you can use your own reconnection logic, this library support callbacks, in this case OnDisconnect callback can be used, you can set it like this:\n```golang\nclient.SetOnDisconnect(func(addr, serverKey string) {\n\t// ... do something\n})\n```\n\n### Features\n* ✅ Support cell and slice as arguments to run get method\n* ✅ Reconnect on failure\n* ✅ Get account state method\n* ✅ Send external message\n* ✅ Get transactions\n* ✅ Deploy contracts\n* ✅ Wallet operations\n* ✅ Cell dictionaries support\n* ✅ MustLoad methods\n* ✅ Parse global config json\n* ✅ Jettons\n* ✅ DNS\n* ✅ ADNL UDP Client/Server\n* ✅ ADNL TCP Client/Server\n* ✅ RLDP Client/Server\n* ✅ TON Sites Client/Server\n* ✅ DHT\n* ✅ Merkle proofs validation and creation\n* ✅ Overlays\n* ✅ TL Parser/Serializer\n* ✅ TL-B Parser/Serializer\n* ✅ Payment channels\n* ✅ Liteserver proofs automatic validation\n* ✅ TVM (Contract execution emulation)\n\n\u003c!-- Badges --\u003e\n[ton-svg]: https://img.shields.io/badge/Based%20on-TON-blue\n[tgc-svg]: https://img.shields.io/badge/Telegram%20-Subscribe-24A1DE\n[tgg-svg]: https://img.shields.io/badge/Telegram%20-Group-blue\n[ton]: https://ton.org\n[tg-chat]: https://t.me/tonutils\n[tg-channel]: https://t.me/tonutilsnews\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxssnick%2Ftonutils-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxssnick%2Ftonutils-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxssnick%2Ftonutils-go/lists"}