<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Salikh Osmanov</title>
    <description>The latest articles on DEV Community by Salikh Osmanov (@a08778).</description>
    <link>https://dev.to/a08778</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2968526%2F7b548d5d-1412-44f1-90b3-2876719d55ea.jpg</url>
      <title>DEV Community: Salikh Osmanov</title>
      <link>https://dev.to/a08778</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/a08778"/>
    <language>en</language>
    <item>
      <title>🔐 Admin Control in TON Stablecoins: What Every User Must Know</title>
      <dc:creator>Salikh Osmanov</dc:creator>
      <pubDate>Sat, 14 Feb 2026 10:16:30 +0000</pubDate>
      <link>https://dev.to/a08778/admin-control-in-ton-stablecoins-what-every-user-must-know-d3p</link>
      <guid>https://dev.to/a08778/admin-control-in-ton-stablecoins-what-every-user-must-know-d3p</guid>
      <description>&lt;h2&gt;
  
  
  🧭 Introduction
&lt;/h2&gt;

&lt;p&gt;One day I needed to choose a stablecoin for use in one of my startups.&lt;br&gt;&lt;br&gt;
Initially, I had only two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tonviewer.com/EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs" rel="noopener noreferrer"&gt;&lt;strong&gt;Tether USD (USDT)&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tonviewer.com/EQAIb6KmdfdDR7CN1GBqVJuP25iCnLKCvBlJ07Evuu2dzP5f" rel="noopener noreferrer"&gt;&lt;strong&gt;Ethena USDe&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are the most popular stablecoins on the TON blockchain.&lt;/p&gt;

&lt;p&gt;To make a proper decision, I decided to explore their source codes.&lt;br&gt;&lt;br&gt;
I was surprised when I saw that &lt;strong&gt;admins of these contracts are able to perform operations that can potentially lead to loss of user funds and that go beyond standard fungible token functionality&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛡️ Stablecoin Admin Permissions
&lt;/h2&gt;

&lt;p&gt;I explored the following smart contracts in detail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ton-blockchain/jetton-contract" rel="noopener noreferrer"&gt;TON Standard Jetton contracts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ton-blockchain/stablecoin-contract" rel="noopener noreferrer"&gt;TON Standard Stablecoin contracts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tonviewer.com/EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs?section=code" rel="noopener noreferrer"&gt;Tether USD contracts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tonviewer.com/EQAIb6KmdfdDR7CN1GBqVJuP25iCnLKCvBlJ07Evuu2dzP5f?section=code" rel="noopener noreferrer"&gt;Ethena USDe contracts&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both stablecoins are based on the stablecoin sample smart contract from the TON Foundation GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ton-blockchain/stablecoin-contract" rel="noopener noreferrer"&gt;https://github.com/ton-blockchain/stablecoin-contract&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;In the README file of the repository, we can find the following text:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This project was created to allow users to exchange and buy assets in the TON DeFi ecosystem for a jetton (token or currency) that is not subject to volatile fluctuations.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;To meet regulatory requirements, the issuer of the tokens must have additional control over the tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Thus this jetton represents a standard TON jetton smart contract with additional functionality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Admin of jetton can make transfers from user's jetton wallet.
&lt;/li&gt;
&lt;li&gt;Admin of jetton can burn user's jettons.
&lt;/li&gt;
&lt;li&gt;Admin of jetton can lock/unlock user's jetton wallet (&lt;code&gt;set_status&lt;/code&gt;). Admin can make transfer and burn even if wallet locked.
&lt;/li&gt;
&lt;li&gt;Admin of jetton can change jetton-minter code and its full data.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;I intentionally made the &lt;strong&gt;“To meet regulatory requirements”&lt;/strong&gt; excerpt bold.&lt;/p&gt;

&lt;p&gt;I think all stablecoins, in order to work normally without restrictions around the world, &lt;strong&gt;have to include the operations mentioned above&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But users have to be aware of that — &lt;strong&gt;they do not have full, exclusive control over their funds&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Implementation Details
&lt;/h2&gt;

&lt;p&gt;USDT contracts’ code is identical to the standard stablecoin contract.&lt;/p&gt;

&lt;p&gt;USDe contracts’ code differs slightly in burn and mint mechanics, but in terms of regulatory features, they are the same.&lt;/p&gt;

&lt;p&gt;If we look at the code, we will see the following operations that the admin can perform in a jetton wallet contract:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;transfer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;burn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set_status&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compared with the standard jetton contract, the standard stablecoin contract has an additional field named &lt;code&gt;status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So now every wallet smart contract has a status.&lt;/p&gt;

&lt;p&gt;There are &lt;strong&gt;4 statuses&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Status = 0&lt;/strong&gt; — No restrictions. The owner can transfer and receive funds. (Default status)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status = 1&lt;/strong&gt; — User cannot send funds from the wallet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status = 2&lt;/strong&gt; — User cannot receive funds to the wallet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status = 3&lt;/strong&gt; — User cannot either send or receive funds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The admin of the stablecoin can set any status for any wallet.&lt;/p&gt;

&lt;p&gt;Even if a wallet is locked for sending funds, the admin of the jetton &lt;strong&gt;can still transfer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But if a wallet is locked for receiving funds, &lt;strong&gt;no one can send funds to that wallet&lt;/strong&gt;, including the admin.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔥 Important Difference from Standard Jetton
&lt;/h3&gt;

&lt;p&gt;In a stablecoin wallet, &lt;strong&gt;only the admin of the jetton can burn funds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the standard jetton contract, &lt;strong&gt;only the owner of the wallet can burn jettons&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is a critical architectural difference.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧾 Conclusion
&lt;/h2&gt;

&lt;p&gt;I think it’s acceptable that an admin can perform some regulatory functions on a stablecoin user’s wallet.&lt;/p&gt;

&lt;p&gt;But users &lt;strong&gt;must be aware&lt;/strong&gt; of these mechanics.&lt;/p&gt;

&lt;p&gt;Stablecoins on TON are &lt;strong&gt;not purely owner-controlled assets&lt;/strong&gt; — they are controlled assets with administrative override.&lt;/p&gt;

&lt;p&gt;Understanding this distinction is critical when choosing which stablecoin to trust and use.&lt;/p&gt;

</description>
      <category>ton</category>
      <category>stablecoin</category>
      <category>smartcontract</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>How many addresses fit into a Cell?</title>
      <dc:creator>Salikh Osmanov</dc:creator>
      <pubDate>Fri, 16 Jan 2026 18:15:40 +0000</pubDate>
      <link>https://dev.to/a08778/how-many-addresses-fit-into-a-cell-2fga</link>
      <guid>https://dev.to/a08778/how-many-addresses-fit-into-a-cell-2fga</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;While developing a smart contract, I needed to store several addresses in persistent storage. At first this looked trivial, but then a simple question came up: &lt;strong&gt;how many addresses can I actually fit into a single cell?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since TON storage is measured in bits and cells, and both storage and message forwarding cost gas, answering this question precisely matters. To do that, we need to look at how addresses are defined and serialized at the TL-b level.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL-b schemes
&lt;/h2&gt;

&lt;p&gt;All address formats used in TON are defined in &lt;a href="https://github.com/a08778/ton/blob/master/crypto/block/block.tlb#L100" rel="noopener noreferrer"&gt;block.tlb&lt;/a&gt;. The relevant schemes are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;addr_none$00 = MsgAddressExt;

addr_extern$01 len:(## 9) external_address:(bits len)
= MsgAddressExt;

anycast_info$_ depth:(#&amp;lt;= 30) { depth &amp;gt;= 1 }
rewrite_pfx:(bits depth) = Anycast;

addr_std$10 anycast:(Maybe Anycast)
workchain_id:int8 address:bits256 = MsgAddressInt;

addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
workchain_id:int32 address:(bits addr_len) = MsgAddressInt;

_ _:MsgAddressInt = MsgAddress;
_ _:MsgAddressExt = MsgAddress;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Address constructors
&lt;/h3&gt;

&lt;p&gt;There are &lt;strong&gt;exactly four address constructors&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;addr_none&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;addr_extern&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;addr_std&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;addr_var&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Theoretical aspects: calculating address size
&lt;/h2&gt;

&lt;p&gt;In this section we calculate &lt;strong&gt;exact bit sizes&lt;/strong&gt; based strictly on the TL-B definitions.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;addr_none&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;addr_none$00 = MsgAddressExt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Constructor tag &lt;code&gt;$00&lt;/code&gt; → &lt;strong&gt;2 bits&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Exact size: 2 bits&lt;/strong&gt;  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;addr_extern&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;addr_extern$01 len:(## 9) external_address:(bits len)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Constructor tag &lt;code&gt;$01&lt;/code&gt; → &lt;strong&gt;2 bits&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;len:(## 9)&lt;/code&gt; → &lt;strong&gt;9 bits&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;external_address:(bits len)&lt;/code&gt; → &lt;strong&gt;len bits&lt;/strong&gt;, where &lt;code&gt;len ∈ [0, 511]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Exact size formula:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 + 9 + len = 11 + len bits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Minimum size:&lt;/strong&gt; &lt;code&gt;len = 0&lt;/code&gt; → &lt;strong&gt;11 bits&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maximum size:&lt;/strong&gt; &lt;code&gt;len = 511&lt;/code&gt; → &lt;strong&gt;522 bits&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;addr_std&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;addr_std$10 anycast:(Maybe Anycast) workchain_id:int8 address:bits256
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breakdown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Constructor tag &lt;code&gt;$10&lt;/code&gt; → &lt;strong&gt;2 bits&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;anycast:(Maybe Anycast)&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Presence flag → &lt;strong&gt;1 bit&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;If present:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;depth:(#&amp;lt;=30)&lt;/code&gt; → &lt;strong&gt;5 bits&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rewrite_pfx:(bits depth)&lt;/code&gt; → &lt;strong&gt;depth bits&lt;/strong&gt;, where &lt;code&gt;depth ∈ [1, 30]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;workchain_id:int8&lt;/code&gt; → &lt;strong&gt;8 bits&lt;/strong&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;address:bits256&lt;/code&gt; → &lt;strong&gt;256 bits&lt;/strong&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Exact size formula:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 + 1 + (anycast ? (5 + depth) : 0) + 8 + 256
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Without anycast (presence bit = 0):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 + 1 + 8 + 256 = 267 bits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;With anycast, maximum depth = 30:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 + 1 + (5 + 30) + 8 + 256 = 302 bits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;addr_var&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
workchain_id:int32 address:(bits addr_len)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Constructor tag &lt;code&gt;$11&lt;/code&gt; → &lt;strong&gt;2 bits&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;anycast:(Maybe Anycast)&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Presence flag → &lt;strong&gt;1 bit&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;If present:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;depth:(#&amp;lt;=30)&lt;/code&gt; → &lt;strong&gt;5 bits&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rewrite_pfx:(bits depth)&lt;/code&gt; → &lt;strong&gt;depth bits&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;addr_len:(## 9)&lt;/code&gt; → &lt;strong&gt;9 bits&lt;/strong&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;workchain_id:int32&lt;/code&gt; → &lt;strong&gt;32 bits&lt;/strong&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;address:(bits addr_len)&lt;/code&gt; → &lt;strong&gt;addr_len bits&lt;/strong&gt;, where &lt;code&gt;addr_len ∈ [0, 511]&lt;/code&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Exact size formula:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 + 1 + (anycast ? (5 + depth) : 0) + 9 + 32 + addr_len
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Without anycast, maximum address length:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 + 1 + 9 + 32 + 511 = 555 bits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;With anycast, maximum depth = 30 and maximum address length:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 + 1 + (5 + 30) + 9 + 32 + 511 = 590 bits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Practical assumptions (what really happens on mainnet)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Anycast is not used
&lt;/h3&gt;

&lt;p&gt;Since &lt;strong&gt;TVM version 10&lt;/strong&gt;, anycast addresses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;are not allowed as message destinations,&lt;/li&gt;
&lt;li&gt;are not allowed in account addresses,&lt;/li&gt;
&lt;li&gt;are no longer supported by address parsing and rewrite instructions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, this means the &lt;code&gt;Maybe Anycast&lt;/code&gt; flag is always &lt;code&gt;0&lt;/code&gt;, and the Anycast payload is never present.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;addr_var&lt;/code&gt; is not used
&lt;/h3&gt;

&lt;p&gt;Currently active workchains (masterchain and basechain):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use &lt;code&gt;addr_std&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;use 256-bit account IDs,&lt;/li&gt;
&lt;li&gt;use small workchain IDs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;addr_var&lt;/code&gt; exists for future extensions and is not used in real contracts today.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical address sizes
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Internal address (&lt;code&gt;addr_std&lt;/code&gt;, real usage)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 (tag)
+ 1 (anycast flag)
+ 8 (workchain_id)
+ 256 (account_id)
= 267 bits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Exact size:&lt;/strong&gt; &lt;strong&gt;267 bits&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This size is fixed.&lt;/p&gt;

&lt;h4&gt;
  
  
  External address (&lt;code&gt;addr_extern&lt;/code&gt;, maximum)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 (tag)
+ 9 (length)
+ 511 (payload)
= 522 bits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;TON defines &lt;strong&gt;four address constructors&lt;/strong&gt;: &lt;code&gt;addr_none&lt;/code&gt;, &lt;code&gt;addr_extern&lt;/code&gt;, &lt;code&gt;addr_std&lt;/code&gt;, and &lt;code&gt;addr_var&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Theoretical address sizes range from &lt;strong&gt;2 bits&lt;/strong&gt; to &lt;strong&gt;590 bits&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;On mainnet today:

&lt;ul&gt;
&lt;li&gt;Anycast is unused.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;addr_var&lt;/code&gt; is unused.&lt;/li&gt;
&lt;li&gt;All internal addresses are &lt;code&gt;addr_std&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;As a result, the &lt;strong&gt;practical internal address size is fixed and exactly&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;➡️ 267 bits&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Knowing this exact value is essential when designing compact storage layouts, estimating gas costs, and deciding how many addresses can fit into a single cell.&lt;/p&gt;

</description>
      <category>tvm</category>
      <category>func</category>
      <category>ton</category>
      <category>tlb</category>
    </item>
    <item>
      <title>3 Types of Authorization in TON Smart Contracts</title>
      <dc:creator>Salikh Osmanov</dc:creator>
      <pubDate>Thu, 04 Dec 2025 20:48:10 +0000</pubDate>
      <link>https://dev.to/a08778/3-types-of-authorization-in-ton-smart-contracts-58k1</link>
      <guid>https://dev.to/a08778/3-types-of-authorization-in-ton-smart-contracts-58k1</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In smart contracts, we often need to allow certain actions only for specific actors.&lt;br&gt;&lt;br&gt;
A simple example is a wallet contract: we must authorize message senders to ensure only valid users can send funds.&lt;/p&gt;

&lt;p&gt;So what options do we have?&lt;br&gt;&lt;br&gt;
In this article, I’d like to show &lt;strong&gt;three common ways to authorize messages&lt;/strong&gt; in TON smart contracts.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. Signature Verification
&lt;/h2&gt;

&lt;p&gt;This mechanism is used for &lt;strong&gt;external messages&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Below is an example in FunC that checks a message signature.&lt;br&gt;&lt;br&gt;
It comes from the standard &lt;strong&gt;wallet-v3&lt;/strong&gt; contract:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/ton-blockchain/ton/blob/d97fc197f07bb0070eeb3e6fcb8137a240ea5365/crypto/smartcont/wallet3-code.fc#L7" rel="noopener noreferrer"&gt;https://github.com/ton-blockchain/ton/blob/d97fc197f07bb0070eeb3e6fcb8137a240ea5365/crypto/smartcont/wallet3-code.fc#L7&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;() recv_external(slice in_msg) impure {
  var signature = in_msg~load_bits(512);
  ;; some code
  var (stored_seqno, stored_subwallet, public_key) =
      (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256));
  ;; 
  throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
  accept_message();
  ;; other code
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, the contract verifies the message’s signature using the &lt;strong&gt;public key stored in the contract’s data&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this cannot be used for internal messages
&lt;/h3&gt;

&lt;p&gt;There are two main reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Smart contracts must be deterministic.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Most cryptographic algorithms rely on randomness, which cannot be generated deterministically inside a smart contract.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Contract storage is public.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Therefore, private keys cannot be stored securely inside the contract.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because of this, signature-based authorization only works for external messages.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Address Storage
&lt;/h2&gt;

&lt;p&gt;This is the most widely used authorization method for &lt;strong&gt;internal messages&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
We simply compare the sender’s address with the address stored in the contract’s storage.&lt;/p&gt;

&lt;p&gt;Example from the standard &lt;strong&gt;NFT Collection&lt;/strong&gt; contract:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/ton-blockchain/nft-contract/blob/0b493104cd547d0fd52b7e6fd3c046fc365fe3d4/nft/nft-collection-editable.fc#L70" rel="noopener noreferrer"&gt;https://github.com/ton-blockchain/nft-contract/blob/0b493104cd547d0fd52b7e6fd3c046fc365fe3d4/nft/nft-collection-editable.fc#L70&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;() recv_internal(cell in_msg_full, slice in_msg_body) impure {
    if (in_msg_body.slice_empty?()) {
        ;; ignore empty messages
        return ();
    }
    slice cs = in_msg_full.begin_parse();
    int flags = cs~load_uint(4);

    if (flags &amp;amp; 1) {
        ;; ignore all bounced messages
        return ();
    }

    slice sender_address = cs~load_msg_addr();

    int op = in_msg_body~load_uint(32);
    int query_id = in_msg_body~load_uint(64);

    var (owner_address, next_item_index, content, nft_item_code, royalty_params) = load_data();

    ;; some code

    throw_unless(401, equal_slices(sender_address, owner_address));

    ;; some code
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contract stores the &lt;strong&gt;owner address&lt;/strong&gt;, and then throws if the sender does not match it.&lt;/p&gt;

&lt;p&gt;This method allows storing multiple authorized addresses for different roles.&lt;br&gt;&lt;br&gt;
However, it is not ideal when we need to authorize &lt;strong&gt;many senders&lt;/strong&gt;, such as in Jetton contracts.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Address Calculation
&lt;/h2&gt;

&lt;p&gt;When a contract must authorize &lt;strong&gt;an arbitrary number of senders&lt;/strong&gt;, we need a different approach.&lt;/p&gt;

&lt;p&gt;A great example is the &lt;strong&gt;Jetton Wallet&lt;/strong&gt; contract.&lt;br&gt;&lt;br&gt;
Whenever jettons are transferred, the receiver must verify whether the sender wallet truly belongs to the same Jetton Master.&lt;/p&gt;

&lt;p&gt;Example from the standard Jetton Wallet:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/ton-blockchain/jetton-contract/blob/d55f228edb0eb477cb4845d67e0dacc6489c6b57/contracts/jetton-wallet.fc#L83" rel="noopener noreferrer"&gt;https://github.com/ton-blockchain/jetton-contract/blob/d55f228edb0eb477cb4845d67e0dacc6489c6b57/contracts/jetton-wallet.fc#L83&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;() receive_jettons(slice in_msg_body, slice sender_address, int my_ton_balance, int msg_value)
    impure inline_ref {
    (int status, int balance, slice owner_address, slice jetton_master_address) = load_data();
    int query_id = in_msg_body~load_query_id();
    int jetton_amount = in_msg_body~load_coins();
    slice from_address = in_msg_body~load_msg_addr();
    slice response_address = in_msg_body~load_msg_addr();

    throw_unless(error::not_valid_wallet,
        equal_slices_bits(jetton_master_address, sender_address)
        |
        equal_slices_bits(
            calculate_user_jetton_wallet_address(
                from_address,
                jetton_master_address,
                my_code()
            ),
            sender_address
        )
    );

    ;; other code
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the contract calls&lt;br&gt;&lt;br&gt;
&lt;code&gt;calculate_user_jetton_wallet_address(from_address, jetton_master_address, my_code())&lt;/code&gt;&lt;br&gt;&lt;br&gt;
and checks the result against the actual sender.&lt;/p&gt;

&lt;p&gt;Note the use of &lt;code&gt;my_code()&lt;/code&gt; — an instruction that returns &lt;strong&gt;the current contract code&lt;/strong&gt; via the c7 register:&lt;br&gt;&lt;br&gt;
&lt;a href="https://docs.ton.org/tvm/registers#c7-%E2%80%94-environment-information-and-global-variables" rel="noopener noreferrer"&gt;https://docs.ton.org/tvm/registers#c7-—-environment-information-and-global-variables&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Important notes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can also store &lt;strong&gt;another contract’s code&lt;/strong&gt; in your storage to calculate addresses for external contracts.&lt;/li&gt;
&lt;li&gt;Sometimes the sender must pass initialization parameters used during deployment.
You must validate these parameters carefully.&lt;/li&gt;
&lt;li&gt;If both contracts use the same known parameter (e.g., admin address), it is safer to &lt;strong&gt;read it from your own storage&lt;/strong&gt;, not from the message.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this article is helpful for newcomers to TON smart-contract development.&lt;br&gt;&lt;br&gt;
Choosing the right authorization strategy is an important part of designing a contract’s architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy coding! 🚀&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>func</category>
      <category>tvm</category>
      <category>ton</category>
      <category>smartcontract</category>
    </item>
    <item>
      <title>A Comprehensive Guide to Implicit Fields in TL-B</title>
      <dc:creator>Salikh Osmanov</dc:creator>
      <pubDate>Thu, 09 Oct 2025 13:01:23 +0000</pubDate>
      <link>https://dev.to/a08778/a-comprehensive-guide-to-implicit-fields-in-tl-b-36ap</link>
      <guid>https://dev.to/a08778/a-comprehensive-guide-to-implicit-fields-in-tl-b-36ap</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this article, we’ll dive deep into the concept of &lt;strong&gt;implicit fields&lt;/strong&gt; in the &lt;strong&gt;TL-B language&lt;/strong&gt; — a critical feature for understanding TON blockchain data structures.  &lt;/p&gt;

&lt;p&gt;When developing smart contracts on TON, TL-B schemas are used to define standardized cell layouts such as &lt;code&gt;CommonMsgInfo&lt;/code&gt;, &lt;code&gt;StateInit&lt;/code&gt;, and many others. Among all aspects of TL-B, implicit fields and their value-assignment rules are some of the trickiest to master.&lt;/p&gt;

&lt;p&gt;Understanding implicit fields is essential for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Correctly interpreting &lt;code&gt;.tlb&lt;/code&gt; schemas
&lt;/li&gt;
&lt;li&gt;Implementing serialization and deserialization logic
&lt;/li&gt;
&lt;li&gt;Writing tools and parsers for TON data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, we’ll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What implicit fields are and how they are defined
&lt;/li&gt;
&lt;li&gt;Where and why they are used
&lt;/li&gt;
&lt;li&gt;The two main usage scenarios (parameterized types and derived values)
&lt;/li&gt;
&lt;li&gt;Constraints and the rules for constraint expressions
&lt;/li&gt;
&lt;li&gt;Best practices and naming conventions
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before you continue, it’s worth reviewing the official TL-B documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.ton.org/v3/documentation/data-formats/tlb/overview" rel="noopener noreferrer"&gt;TL-B Language Overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ton-blockchain.github.io/docs/#/overviews/TL-B" rel="noopener noreferrer"&gt;General Overview of TL-B&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most examples in this article are drawn from the &lt;strong&gt;official TON TL-B schemas&lt;/strong&gt; and documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb" rel="noopener noreferrer"&gt;&lt;code&gt;block.tlb&lt;/code&gt;&lt;/a&gt; — defines the structure of blocks and block headers
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ton-blockchain/ton/blob/master/crypto/tl/hashmap.tlb" rel="noopener noreferrer"&gt;&lt;code&gt;hashmap.tlb&lt;/code&gt;&lt;/a&gt; — defines hashmaps and their serialization in TL-B
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ton-blockchain/ton/blob/master/crypto/tl/boc.tlb" rel="noopener noreferrer"&gt;&lt;code&gt;boc.tlb&lt;/code&gt;&lt;/a&gt; — defines the Bag of Cells (BOC) container format
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For deeper understanding of how these schemas are used in TON layouts, consult the official documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.ton.org/v3/documentation/data-formats/tlb/types" rel="noopener noreferrer"&gt;TL-B Types &amp;amp; Type System&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.ton.org/v3/documentation/data-formats/layout/messages" rel="noopener noreferrer"&gt;Message Layouts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.ton.org/v3/documentation/data-formats/layout/transactions" rel="noopener noreferrer"&gt;Transaction Layouts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.ton.org/v3/documentation/data-formats/layout/blocks" rel="noopener noreferrer"&gt;Block Layouts&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I’ll use TypeScript-style pseudocode to illustrate TL-B objects.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Understanding Implicit Fields in TL-B
&lt;/h2&gt;

&lt;p&gt;According to the official TL-B documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Some fields may be implicit. These fields are defined within curly braces &lt;code&gt;{ }&lt;/code&gt;, indicating that they are not directly serialized. Instead, their values must be deduced from other data, usually the parameters of the type being serialized.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before diving deeper, let’s clarify a term used throughout this article — the &lt;strong&gt;resulting bitstring&lt;/strong&gt; (or simply &lt;em&gt;bitstring&lt;/em&gt;).&lt;br&gt;&lt;br&gt;
This is the binary string produced after serializing an object according to its TL-B definition. It represents the actual bits written into a cell and is used to reconstruct the object during deserialization.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the corresponding TL-B combinator declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constructor1$10 x:(## 4) y:(## 6) = A;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Serialization proceeds as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first two bits &lt;code&gt;"10"&lt;/code&gt; represent the constructor tag.
&lt;/li&gt;
&lt;li&gt;Then we encode &lt;code&gt;x = 2&lt;/code&gt; using 4 bits: &lt;code&gt;0010&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Then we encode &lt;code&gt;y = 3&lt;/code&gt; using 6 bits: &lt;code&gt;000011&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The resulting bitstring is:&lt;br&gt;&lt;br&gt;
&lt;code&gt;"10" + "0010" + "000011"&lt;/code&gt; → &lt;strong&gt;&lt;code&gt;100010000011&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What Are Implicit Fields?
&lt;/h2&gt;

&lt;p&gt;TL-B has two kinds of fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explicit fields&lt;/strong&gt; — values are &lt;em&gt;represented&lt;/em&gt; in the resulting bitstring.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implicit fields&lt;/strong&gt; — values are &lt;em&gt;not represented&lt;/em&gt; in the bitstring but are derived or passed as parameters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implicit fields make TL-B schemas more compact and expressive. They let you describe structural relationships and parameter dependencies without wasting bits on redundant data.&lt;/p&gt;


&lt;h2&gt;
  
  
  Defining Implicit Fields
&lt;/h2&gt;

&lt;p&gt;Curly braces &lt;code&gt;{ }&lt;/code&gt; in TL-B can serve several purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Defining &lt;strong&gt;implicit fields&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Expressing &lt;strong&gt;constraints&lt;/strong&gt; on values
&lt;/li&gt;
&lt;li&gt;Declaring &lt;strong&gt;computed or returned&lt;/strong&gt; fields&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The general syntax for an implicit field is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ field_name : field_type }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Allowed Field Types
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Natural Numbers (&lt;code&gt;#&lt;/code&gt;)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  { x:# }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;#&lt;/code&gt; represents a natural number (usually a 32-bit unsigned integer).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type Parameters (&lt;code&gt;Type&lt;/code&gt;)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  { X:Type }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Naming Conventions
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field Type&lt;/th&gt;
&lt;th&gt;Naming Convention&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Natural number&lt;/td&gt;
&lt;td&gt;lowercase&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{n:#}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type parameter&lt;/td&gt;
&lt;td&gt;uppercase&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{X:Type}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Constraints in TL-B
&lt;/h2&gt;

&lt;p&gt;In TL-B, &lt;strong&gt;constraints&lt;/strong&gt; are expressions enclosed in &lt;code&gt;{ }&lt;/code&gt; that specify &lt;em&gt;conditions&lt;/em&gt; a value must satisfy.&lt;br&gt;&lt;br&gt;
They are not serialized — instead, they act as logical rules that implementations must enforce during &lt;strong&gt;serialization&lt;/strong&gt; or &lt;strong&gt;deserialization&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Constraints are widely used in TON schemas to ensure consistency between related fields.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Boolean constraints
&lt;/h3&gt;

&lt;p&gt;A simple comparison or logical assertion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flags:(## 8) { flags &amp;lt;= 1 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that the 8-bit field &lt;code&gt;flags&lt;/code&gt; must not exceed 1.&lt;br&gt;&lt;br&gt;
Such constraints are checked during serialization or parsing, ensuring schema consistency.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Relational constraints
&lt;/h3&gt;

&lt;p&gt;Constraints can express relationships between multiple fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;seq_no:# vert_seq_no:# { vert_seq_no &amp;gt;= vert_seqno_incr }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;vert_seq_no&lt;/code&gt; must be greater than or equal to &lt;code&gt;vert_seqno_incr&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
No extra bits are stored — this condition just governs valid combinations of values.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Derived (computed) constraints
&lt;/h3&gt;

&lt;p&gt;Constraints can also &lt;em&gt;define&lt;/em&gt; the value of an implicit field, indicated by a &lt;strong&gt;tilde (&lt;code&gt;~&lt;/code&gt;)&lt;/strong&gt; operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ prev_seq_no:# } { ~prev_seq_no + 1 = seq_no }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that &lt;code&gt;prev_seq_no&lt;/code&gt; is implicitly defined by&lt;br&gt;&lt;br&gt;
&lt;code&gt;prev_seq_no = seq_no − 1&lt;/code&gt;&lt;br&gt;&lt;br&gt;
(expressed as &lt;code&gt;~prev_seq_no + 1 = seq_no&lt;/code&gt;, since &lt;code&gt;−&lt;/code&gt; is not allowed in TL-B).  &lt;/p&gt;

&lt;p&gt;It’s not read from the bitstring — instead, it’s &lt;strong&gt;derived&lt;/strong&gt; from another value.&lt;/p&gt;

&lt;p&gt;You can also use multiplication (&lt;code&gt;*&lt;/code&gt;) to express relationships that would otherwise use division.&lt;br&gt;&lt;br&gt;
Since &lt;code&gt;/&lt;/code&gt; is not permitted in TL-B, expressions such as “&lt;code&gt;x = y / 2&lt;/code&gt;” must be rewritten using multiplication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ ~x * 2 = y }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This constraint means &lt;code&gt;x = y / 2&lt;/code&gt;, but expressed through the only allowed operation &lt;code&gt;*&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
This pattern appears in TL-B when the number of elements, bits, or cells must be a multiple or divisor of another count.&lt;/p&gt;

&lt;p&gt;If the tilde (&lt;code&gt;~&lt;/code&gt;) operator still confuses you, I’ve written a detailed explanation of it and its usage in TL-B here:  👉 &lt;a href="https://dev.to/a08778/negate-operator-in-tl-b-explained-hl8"&gt;Negate Operator (~) in TL-B Explained&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Fixed-value constraints
&lt;/h3&gt;

&lt;p&gt;Sometimes, a constraint simply fixes a constant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ ~len = 8 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is equivalent to declaring that the implicit field &lt;code&gt;len&lt;/code&gt; always equals 8.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary of Constraint Usage
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Boolean&lt;/td&gt;
&lt;td&gt;Limit a value&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ flags &amp;lt;= 1 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relational&lt;/td&gt;
&lt;td&gt;Relate two fields&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ vert_seq_no &amp;gt;= vert_seqno_incr }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Derived&lt;/td&gt;
&lt;td&gt;Define one value from another&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ ~prev_seq_no + 1 = seq_no }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Hard-coded constant&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ ~len = 8 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Constraints are one of the most elegant features of TL-B — they make schemas &lt;strong&gt;self-validating&lt;/strong&gt;, documenting both data layout and expected relationships.&lt;/p&gt;




&lt;h2&gt;
  
  
  Placement of Implicit Field Definitions
&lt;/h2&gt;

&lt;p&gt;By convention, &lt;strong&gt;implicit field definitions&lt;/strong&gt; — that is, parts like &lt;code&gt;{ prev_seq_no:# }&lt;/code&gt; which &lt;em&gt;declare&lt;/em&gt; an implicit variable — are usually placed at the &lt;strong&gt;beginning&lt;/strong&gt; of a combinator declaration.  &lt;/p&gt;

&lt;p&gt;These definitions introduce implicit parameters or values that may later be used by other fields or constraints in the same combinator.&lt;br&gt;&lt;br&gt;
However, this placement is a convention, not a strict requirement — they can appear anywhere within the definition as long as references remain valid.&lt;/p&gt;

&lt;p&gt;In contrast, &lt;strong&gt;constraints&lt;/strong&gt; (for example, &lt;code&gt;{ ~prev_seq_no + 1 = seq_no }&lt;/code&gt;) typically follow field definitions, since they describe logical relationships among already declared fields.&lt;/p&gt;

&lt;p&gt;Example excerpt from &lt;a href="https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb" rel="noopener noreferrer"&gt;&lt;code&gt;block.tlb&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;block_info#9bc7a987 version:uint32
  not_master:(## 1)
  after_merge:(## 1) before_split:(## 1)
  after_split:(## 1)
  want_split:Bool want_merge:Bool
  key_block:Bool vert_seqno_incr:(## 1)
  flags:(## 8) { flags &amp;lt;= 1 }
  seq_no:# vert_seq_no:# { vert_seq_no &amp;gt;= vert_seqno_incr }
  { prev_seq_no:# } { ~prev_seq_no + 1 = seq_no }
  shard:ShardIdent gen_utime:uint32
  start_lt:uint64 end_lt:uint64
  gen_validator_list_hash_short:uint32
  gen_catchain_seqno:uint32
  min_ref_mc_seqno:uint32
  prev_key_block_seqno:uint32
  gen_software:flags.0?GlobalVersion
  master_ref:not_master?^BlkMasterInfo
  prev_ref:^(BlkPrevInfo after_merge)
  prev_vert_ref:vert_seqno_incr?^(BlkPrevInfo 0)
  = BlockInfo;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;{ prev_seq_no:# }&lt;/code&gt; and &lt;code&gt;{ ~prev_seq_no + 1 = seq_no }&lt;/code&gt; demonstrate &lt;strong&gt;implicit definition&lt;/strong&gt; combined with a &lt;strong&gt;constraint&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Obtaining Values of Implicit Fields
&lt;/h2&gt;

&lt;p&gt;Suppose we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {length:#} a:(## length) ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where does &lt;code&gt;length&lt;/code&gt; come from?  &lt;/p&gt;

&lt;p&gt;Implicit fields get their values in &lt;strong&gt;two main ways&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Through type parameters&lt;/strong&gt; — values are passed when instantiating a type.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Through constraints or derivation&lt;/strong&gt; — values are computed or logically determined from other fields.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example 1: Parameterized Implicit Field
&lt;/h3&gt;

&lt;p&gt;Incorrect definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ val:(## length) = IntVal length; // invalid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;length&lt;/code&gt; is not declared, so this schema is invalid.&lt;/p&gt;

&lt;p&gt;Correct version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {length:#} val:(## length) = IntVal length;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;length&lt;/code&gt; is an implicit parameter — it’s &lt;em&gt;passed in&lt;/em&gt; rather than serialized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 2: Derived (Calculated) Implicit Field
&lt;/h3&gt;

&lt;p&gt;We can define implicit fields whose values are &lt;em&gt;derived&lt;/em&gt; from others using the tilde (&lt;code&gt;~&lt;/code&gt;) operator.&lt;br&gt;&lt;br&gt;
For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {length:#} val:(## length) { ~length = 8 } = Int8BitVal;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;{ ~length = 8 }&lt;/code&gt; acts as a &lt;strong&gt;constraint&lt;/strong&gt;, meaning “&lt;code&gt;length&lt;/code&gt; must equal 8.”&lt;br&gt;&lt;br&gt;
Implementations can interpret this as a computed or fixed value.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example 3: Returned Implicit Value
&lt;/h3&gt;

&lt;p&gt;Sometimes a field’s value is returned by another type using the &lt;code&gt;~&lt;/code&gt; notation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {length:#} val:(## length) = IntVal length ~val;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that &lt;code&gt;IntVal&lt;/code&gt; returns its &lt;code&gt;val&lt;/code&gt;, making it accessible to the enclosing type.&lt;/p&gt;

&lt;p&gt;We can then use this returned value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {v:#} a:(IntVal 8 ~v) b:(## v) = A;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;v&lt;/code&gt; is an implicit field that obtains its value from &lt;code&gt;IntVal 8 ~v&lt;/code&gt;, and that value determines the bit length of &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Serialization and Deserialization
&lt;/h2&gt;

&lt;p&gt;It’s important to distinguish between &lt;strong&gt;parameterized&lt;/strong&gt; and &lt;strong&gt;derived&lt;/strong&gt; implicit fields.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parameterized fields&lt;/strong&gt; must be known &lt;strong&gt;before serialization&lt;/strong&gt; or &lt;strong&gt;deserialization&lt;/strong&gt;, since their values define bit sizes or type choices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Derived fields&lt;/strong&gt; are &lt;strong&gt;computed during deserialization&lt;/strong&gt; — they are &lt;em&gt;not read&lt;/em&gt; from the bitstring but &lt;em&gt;inferred&lt;/em&gt; from other data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: Parameterized Field
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {x:#} my_val:(## x) = A x;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we serialize:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;my_val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We must know &lt;code&gt;x = 6&lt;/code&gt; before serialization to encode the correct number of bits.&lt;br&gt;&lt;br&gt;
During deserialization, we also need &lt;code&gt;x&lt;/code&gt; to know how many bits to read.&lt;/p&gt;

&lt;p&gt;Resulting bitstring: 6 bits representing the binary form of 5 → &lt;code&gt;000101&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Derived Field
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {a:#} my_val:(## x) { ~x = a + 1 } = A;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;x&lt;/code&gt; is &lt;strong&gt;not provided&lt;/strong&gt; externally.&lt;br&gt;&lt;br&gt;
Instead, during deserialization, after reading &lt;code&gt;a&lt;/code&gt;, we can compute &lt;code&gt;x = a + 1&lt;/code&gt; and use it to read &lt;code&gt;my_val&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thus, calculated implicit fields are &lt;strong&gt;derived&lt;/strong&gt;, not &lt;strong&gt;deserialized&lt;/strong&gt; — their values are reconstructed logically.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Case&lt;/th&gt;
&lt;th&gt;Source of Value&lt;/th&gt;
&lt;th&gt;Serialization Behavior&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Explicit field&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Directly stored in bitstring&lt;/td&gt;
&lt;td&gt;Serialized&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a:(## 8)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Implicit (parameterized)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Passed as type parameter&lt;/td&gt;
&lt;td&gt;Not serialized&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{n:#} value:(## n)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Implicit (derived)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Computed from other fields&lt;/td&gt;
&lt;td&gt;Not serialized&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ ~x = a + 1 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Constraint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Restriction or relation&lt;/td&gt;
&lt;td&gt;Not serialized&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ flags &amp;lt;= 1 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Returned value&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Returned by nested type&lt;/td&gt;
&lt;td&gt;Not serialized&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Type ~field&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Implicit fields and constraints are key features of TL-B that make TON schemas compact yet expressive.&lt;br&gt;&lt;br&gt;
They allow you to parameterize structures, enforce logical relationships, and define derived values — all without consuming extra bits in serialization.&lt;/p&gt;

&lt;p&gt;When implementing parsers or code generators for TL-B, always remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Implicit ≠ serialized&lt;/strong&gt; — their values come from parameters or computation.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constraint expressions&lt;/strong&gt; are limited: use &lt;code&gt;+&lt;/code&gt; and &lt;code&gt;*&lt;/code&gt; only, and express subtraction or division through equivalent additive or multiplicative forms.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constraints&lt;/strong&gt; &lt;code&gt;{ ~x = expr }&lt;/code&gt; and &lt;code&gt;{ condition }&lt;/code&gt; define logical relationships, not procedural code.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Placement is flexible&lt;/strong&gt;, though usually at the beginning for clarity.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mastering implicit fields and constraints will make your understanding of TON’s TL-B language much deeper and your tools more robust.&lt;/p&gt;

</description>
      <category>tlb</category>
      <category>tvm</category>
      <category>func</category>
      <category>ton</category>
    </item>
    <item>
      <title>Negate Operator (`~`) in TL-B, Explained</title>
      <dc:creator>Salikh Osmanov</dc:creator>
      <pubDate>Wed, 17 Sep 2025 14:29:45 +0000</pubDate>
      <link>https://dev.to/a08778/negate-operator-in-tl-b-explained-hl8</link>
      <guid>https://dev.to/a08778/negate-operator-in-tl-b-explained-hl8</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The negate operator (&lt;code&gt;~&lt;/code&gt;, often called the “tilde”) is one of the trickiest parts of &lt;strong&gt;&lt;a href="https://docs.ton.org/v3/documentation/data-formats/tlb/tl-b-language" rel="noopener noreferrer"&gt;TL-B&lt;/a&gt;&lt;/strong&gt;. It shows up all over TON schemas, and understanding it is essential for reading schemas, implementing serializers/deserializers, and building tooling.&lt;/p&gt;

&lt;p&gt;Before diving in, it’s worth skimming:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.ton.org/v3/documentation/data-formats/tlb/tl-b-language" rel="noopener noreferrer"&gt;TL-B Language Specification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ton-blockchain.github.io/docs/#/overviews/TL-B" rel="noopener noreferrer"&gt;General Overview of TL-B&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And browsing real &lt;code&gt;.tlb&lt;/code&gt; schemas in TON repositories:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb" rel="noopener noreferrer"&gt;block.tlb&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/disintar/ton/blob/master/crypto/tl/boc.tlb" rel="noopener noreferrer"&gt;boc.tlb&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/disintar/ton/blob/master/crypto/tl/hashmap.tlb" rel="noopener noreferrer"&gt;hashmap.tlb&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Examples below use TypeScript-style pseudo-objects for clarity.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Where &lt;code&gt;~&lt;/code&gt; can appear—and what it does
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;~&lt;/code&gt; appears in two places, with different roles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inside curly braces &lt;code&gt;{ … }&lt;/code&gt;&lt;/strong&gt; on the &lt;strong&gt;left (fields) side&lt;/strong&gt; of a combinator
This is a &lt;em&gt;constraint/equation context&lt;/em&gt;. You can:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Define&lt;/strong&gt; the value of an &lt;em&gt;implicit&lt;/em&gt; field (not serialized) by equation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constrain&lt;/strong&gt; the value of an &lt;em&gt;explicit&lt;/em&gt; field (serialized) by equation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;code&gt;{ ~x = expr }&lt;/code&gt; does &lt;strong&gt;not “override”&lt;/strong&gt; a field value.&lt;br&gt;&lt;br&gt;
It &lt;strong&gt;requires&lt;/strong&gt; that the serialized value equals &lt;code&gt;expr&lt;/code&gt;. If it doesn’t, validation fails.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;On the right (type name) side&lt;/strong&gt; after &lt;code&gt;= …&lt;/code&gt;
This is a &lt;em&gt;return context&lt;/em&gt;. &lt;code&gt;~expr&lt;/code&gt; makes the constructor &lt;strong&gt;return&lt;/strong&gt; an integer value that outer types can use as a parameter. Returned values don’t get serialized; they’re outputs from a type.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Using &lt;code&gt;~&lt;/code&gt; in field/constraint equations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Constraint on an explicit field
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ val:(## 8) { ~val = 2 } = IntVal;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;val&lt;/code&gt; is serialized as 8 bits.
&lt;/li&gt;
&lt;li&gt;The constraint requires &lt;code&gt;val == 2&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is equivalent to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ val:(## 8) { val = 2 } = IntVal;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;strong&gt;explicit fields&lt;/strong&gt;, you can use constraints &lt;strong&gt;with or without &lt;code&gt;~&lt;/code&gt;&lt;/strong&gt;. Both mean the same thing: the serialized value must satisfy the condition.&lt;/p&gt;




&lt;h3&gt;
  
  
  Defining an implicit field
&lt;/h3&gt;

&lt;p&gt;Here’s a valid case with constant addition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {limit:#} size:(## 8) { ~limit = size + 1 } = Sized;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;limit&lt;/code&gt; is implicit.
&lt;/li&gt;
&lt;li&gt;It’s defined as one more than the serialized &lt;code&gt;size&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another valid case with constant multiplication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {bits:#} bytes:(## 8) { ~bits = bytes * 8 } = ByteSized;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bits&lt;/code&gt; is implicit.
&lt;/li&gt;
&lt;li&gt;It’s always &lt;code&gt;8 × bytes&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here’s the &lt;strong&gt;real &lt;code&gt;hm_edge&lt;/code&gt; definition from &lt;code&gt;hashmap.tlb&lt;/code&gt;&lt;/strong&gt; showing variable + variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hm_edge#_ {n:#} {X:Type} {l:#} {m:#} 
  label:(HmLabel ~l n) { n = (~m) + l } 
  node:(HashmapNode m X) 
= Hashmap n X;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;n&lt;/code&gt;, &lt;code&gt;l&lt;/code&gt;, &lt;code&gt;m&lt;/code&gt; are implicit parameters.
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;label&lt;/code&gt; encodes a prefix of length &lt;code&gt;l&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{ n = (~m) + l }&lt;/code&gt; is a constraint: the total key length &lt;code&gt;n&lt;/code&gt; is equal to the remaining part size &lt;code&gt;~m&lt;/code&gt; plus the prefix length &lt;code&gt;l&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;node&lt;/code&gt; encodes the subtree for the remaining &lt;code&gt;m&lt;/code&gt; bits.
&lt;/li&gt;
&lt;li&gt;The type returns &lt;code&gt;Hashmap n X&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This shows that &lt;strong&gt;variable + variable is legal in TL-B equations&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Allowed operators in these equations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Addition &lt;code&gt;+&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;constant + variable ✅
&lt;/li&gt;
&lt;li&gt;variable + constant ✅
&lt;/li&gt;
&lt;li&gt;variable + variable ✅ (as in &lt;code&gt;n = (~m) + l&lt;/code&gt;)
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Multiplication &lt;code&gt;*&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;constant × variable ✅
&lt;/li&gt;
&lt;li&gt;variable × variable ❌ (not supported)
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Equality &lt;code&gt;=&lt;/code&gt;&lt;/strong&gt; (to form the equation)&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Not allowed&lt;/strong&gt;: subtraction (&lt;code&gt;-&lt;/code&gt;), division (&lt;code&gt;/&lt;/code&gt;), comparisons (&lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, etc.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Valid patterns&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ ~a = 2 }
{ ~a = b }
{ ~a = b + 1 }
{ ~a + 1 = b }     // equivalent to a = b - 1
{ ~a = 2 * b }
{ ~a * 2 = b }     // equivalent to a = b / 2
{ n = (~m) + l }   // variable + variable (as in hashmap.tlb)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Using with Type Parameters
&lt;/h2&gt;

&lt;p&gt;First, let’s recall how parameters work for types.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do variables work?
&lt;/h3&gt;

&lt;p&gt;If we declare the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {size:#} a:(## size) = A size;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To &lt;strong&gt;serialize&lt;/strong&gt;, we must provide the value of the &lt;code&gt;size&lt;/code&gt; parameter. The object we want to serialize might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After serialization we get the following bitstring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00011000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the binary representation of the value &lt;code&gt;24&lt;/code&gt; (&lt;code&gt;a&lt;/code&gt; field), written using 8 bits (as specified by the &lt;code&gt;size&lt;/code&gt; parameter).&lt;/p&gt;

&lt;p&gt;As we can see, the value of a parameter must be known &lt;strong&gt;before&lt;/strong&gt; serializing an object.&lt;/p&gt;

&lt;p&gt;The same is true when we want to &lt;strong&gt;deserialize&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Suppose we have the following bitstring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0010000101
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We must know how many bits to take in order to determine the value of the &lt;code&gt;a&lt;/code&gt; field.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the &lt;code&gt;size&lt;/code&gt; parameter’s value is &lt;code&gt;3&lt;/code&gt;, then we take the first 3 bits (&lt;code&gt;001&lt;/code&gt;) → &lt;code&gt;a = 1&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;size&lt;/code&gt; is &lt;code&gt;4&lt;/code&gt;, then we take the first 4 bits (&lt;code&gt;0010&lt;/code&gt;) → &lt;code&gt;a = 2&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, parameters of a type must be known for both serialization and deserialization.&lt;/p&gt;




&lt;h3&gt;
  
  
  Returning a value instead of passing a parameter
&lt;/h3&gt;

&lt;p&gt;If we set a parameter with the negate operator (&lt;code&gt;~&lt;/code&gt;) in front of it, then we don’t have to provide the value explicitly. Instead, the type will &lt;em&gt;return&lt;/em&gt; a value that can be used as a parameter.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ val:(## 8) = IntVal ~val;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the constructor “returns” the value of the &lt;code&gt;val&lt;/code&gt; field.&lt;/p&gt;




&lt;h3&gt;
  
  
  Example of usage
&lt;/h3&gt;

&lt;p&gt;Suppose we have the following type declaration representing a cart item:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ id:# price:(## 16) quantity:(## 8) = Item;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is simple — we just have 3 properties. An object might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s define a cart type that can contain &lt;code&gt;n&lt;/code&gt; items:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {n:#} items:(n * Item) = Cart n;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;n&lt;/code&gt; is implicit and sets the number of items. We pass the value through a parameter.&lt;/p&gt;

&lt;p&gt;But suppose we want to serialize the number of items instead of passing &lt;code&gt;n&lt;/code&gt;. That means we should use an explicit field rather than an implicit one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ n:# items:(n * Item) = Cart;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can make the cart more advanced by introducing a separate type for metadata, e.g., storing the number of items (and potentially discounts, etc.):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ items_count:# = CartMetaData;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But to connect it, we must &lt;em&gt;return&lt;/em&gt; the value of &lt;code&gt;items_count&lt;/code&gt; so it can be used in the &lt;code&gt;Cart&lt;/code&gt; type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ id:# price:(## 16) quantity:(## 8) = Item;
_ items_count:# = CartMetaData ~items_count;
_ metadata:CartMetaData ~n items:(n * Item) = Cart;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;n&lt;/code&gt; field in &lt;code&gt;Cart&lt;/code&gt; is not implicit here, because its value is serialized in the bitstring.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CartMetaData&lt;/code&gt; returns &lt;code&gt;items_count&lt;/code&gt;, which is then passed as &lt;code&gt;n&lt;/code&gt; to the &lt;code&gt;Cart&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;my_cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;items_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;172&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ Reminder: all bits are stored in a Cell, and the size must not exceed 1023 bits. Larger objects must be split across cells.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Returning an expression
&lt;/h3&gt;

&lt;p&gt;You can also return expressions, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ a:# b:# = TwoNat ~(a + b);
_ {sum:#} numbers:(TwoNat ~sum) = Example;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TwoNat&lt;/code&gt; encapsulates two numbers.
&lt;/li&gt;
&lt;li&gt;It also &lt;em&gt;returns&lt;/em&gt; their sum, which can be used in another type.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Returning a constant
&lt;/h3&gt;

&lt;p&gt;You can return constants as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ a:# = A ~4;
_ {x:#} b:(A ~x) = B;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;A&lt;/code&gt; always returns &lt;code&gt;4&lt;/code&gt;. Therefore, the implicit variable &lt;code&gt;x&lt;/code&gt; in &lt;code&gt;B&lt;/code&gt; will always be &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Optional use
&lt;/h3&gt;

&lt;p&gt;Unlike type parameters, returned values are &lt;strong&gt;optional&lt;/strong&gt;. You may use them or simply ignore them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ val:# = A ~val;
_ a:A b:# = A_and_B;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although &lt;code&gt;A&lt;/code&gt; returns the value of its &lt;code&gt;val&lt;/code&gt; field, &lt;code&gt;A_and_B&lt;/code&gt; does not use it.&lt;/p&gt;

&lt;p&gt;Even when parameters are present, returned values may still be omitted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {length:#} val:(## length) = A ~val length;
_ a:(A 8) b:# = A_and_B;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;8&lt;/code&gt; is the parameter passed to &lt;code&gt;A&lt;/code&gt; as its &lt;code&gt;length&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;A&lt;/code&gt; also returns &lt;code&gt;val&lt;/code&gt;, but &lt;code&gt;A_and_B&lt;/code&gt; doesn’t use it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Recursive expression
&lt;/h2&gt;

&lt;p&gt;Now let’s look at the case when the negate operator is used to recursively serialize an object or deserialize a bitstring.&lt;/p&gt;

&lt;p&gt;The most common example is the &lt;strong&gt;unary&lt;/strong&gt; type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;unary_zero$0 = Unary ~0;
unary_succ$1 {n:#} x:(Unary ~n) = Unary ~(n + 1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This effectively means the following expansions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;unary_zero$0                       = Unary ~0;
unary_succ$1 {n:#} x:(Unary ~0)    = Unary ~1;
unary_succ$1 {n:#} x:(Unary ~1)    = Unary ~2;
unary_succ$1 {n:#} x:(Unary ~2)    = Unary ~3;
…
unary_succ$1 {n:#} x:(Unary ~n)    = Unary ~(n + 1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In other words: each time we parse a &lt;code&gt;unary_succ&lt;/code&gt;, we return &lt;strong&gt;one more&lt;/strong&gt; than what we get after deserializing the next bit of the bitstring.&lt;/p&gt;




&lt;h3&gt;
  
  
  Using Unary in another type
&lt;/h3&gt;

&lt;p&gt;Suppose we use &lt;code&gt;Unary&lt;/code&gt; in the following type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_ {l:#} len:(Unary ~l) = Example;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s try to deserialize the bitstring &lt;code&gt;110&lt;/code&gt; into an object of type &lt;code&gt;Example&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
We’ll build it step by step as a TypeScript object.&lt;/p&gt;


&lt;h3&gt;
  
  
  Step 1 — initialize
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Example&lt;/code&gt; has no tag prefix, so we can start with an empty object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* … */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;l&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;len&lt;/code&gt; is of type &lt;code&gt;Unary&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;l&lt;/code&gt; is an implicit field, equal to the value returned by &lt;code&gt;len&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Step 2 — first bit
&lt;/h3&gt;

&lt;p&gt;The first bit of the bitstring is &lt;code&gt;1&lt;/code&gt;, so we use &lt;code&gt;unary_succ&lt;/code&gt;. That gives us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* … */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;n&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;l&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;n&lt;/code&gt; is returned.
&lt;/li&gt;
&lt;li&gt;Its value is &lt;code&gt;this.x.n + 1&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It would be more intuitive to write the schema as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;unary_succ$1 {n:#} x:(Unary ~(n-1)) = Unary ~n;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But two problems arise:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We can’t use calculations like &lt;code&gt;(n-1)&lt;/code&gt; in field declarations.
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;-&lt;/code&gt; operator is not supported in TL-B.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Step 3 — recurse
&lt;/h3&gt;

&lt;p&gt;The remaining bitstring is &lt;code&gt;10&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
The next bit is &lt;code&gt;1&lt;/code&gt;, so again we apply &lt;code&gt;unary_succ&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;n&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;n&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;l&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Step 4 — base case
&lt;/h3&gt;

&lt;p&gt;The last bit is &lt;code&gt;0&lt;/code&gt;, which means we use &lt;code&gt;unary_zero&lt;/code&gt;. That returns &lt;code&gt;0&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Final object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="na"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;n&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;n&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;l&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;n = 0&lt;/code&gt; because &lt;code&gt;unary_zero&lt;/code&gt; returns &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;p&gt;If we run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get &lt;code&gt;2&lt;/code&gt;, which means &lt;code&gt;len:(Unary ~2)&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;Indeed, the bitstring &lt;code&gt;110&lt;/code&gt; contains &lt;strong&gt;two &lt;code&gt;1&lt;/code&gt; bits&lt;/strong&gt; before the terminating &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{ ~val = 2 }&lt;/code&gt; vs &lt;code&gt;{ val = 2 }&lt;/code&gt; → ✅ both work on explicit fields.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;{ ~val = 2 }&lt;/code&gt; &lt;strong&gt;checks&lt;/strong&gt;, it doesn’t assign.
&lt;/li&gt;
&lt;li&gt;Addition: variable + variable ✅ (e.g. &lt;code&gt;n = (~m) + l&lt;/code&gt; in &lt;code&gt;hashmap.tlb&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Multiplication: only constant × variable ✅, variable × variable ❌.
&lt;/li&gt;
&lt;li&gt;No subtraction, division, or comparisons.
&lt;/li&gt;
&lt;li&gt;Returned values (&lt;code&gt;~val&lt;/code&gt;) are optional.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The negate operator &lt;code&gt;~&lt;/code&gt; has two roles:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;{ … }&lt;/code&gt;, it defines implicit fields or enforces constraints.
&lt;/li&gt;
&lt;li&gt;On the right side of a type, it returns integers for outer contexts.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For &lt;strong&gt;explicit fields&lt;/strong&gt;, constraints can be written &lt;strong&gt;with or without &lt;code&gt;~&lt;/code&gt;&lt;/strong&gt; — both are valid and equivalent.&lt;br&gt;&lt;br&gt;
For &lt;strong&gt;implicit fields&lt;/strong&gt;, you must use &lt;code&gt;~&lt;/code&gt; to define their values.  &lt;/p&gt;

&lt;p&gt;And as the &lt;code&gt;hm_edge&lt;/code&gt; constructor in &lt;code&gt;hashmap.tlb&lt;/code&gt; shows, &lt;code&gt;variable + variable&lt;/code&gt; is fully supported in TL-B equations — while &lt;code&gt;variable × variable&lt;/code&gt; remains unsupported.  &lt;/p&gt;

&lt;p&gt;Once you know these rules (and the limits of allowed operators), TL-B schemas with &lt;code&gt;~&lt;/code&gt; become much clearer to read and implement.  &lt;/p&gt;

</description>
      <category>tlb</category>
      <category>tvm</category>
      <category>func</category>
      <category>ton</category>
    </item>
    <item>
      <title>Computing the actual size of a TON smart contract storage</title>
      <dc:creator>Salikh Osmanov</dc:creator>
      <pubDate>Wed, 30 Jul 2025 20:02:13 +0000</pubDate>
      <link>https://dev.to/a08778/computing-the-actual-size-of-a-ton-smart-contract-storage-4p5c</link>
      <guid>https://dev.to/a08778/computing-the-actual-size-of-a-ton-smart-contract-storage-4p5c</guid>
      <description>&lt;p&gt;Sometimes, it’s useful to know &lt;strong&gt;the exact size of the data&lt;/strong&gt; stored by a smart contract. A contract must pay a &lt;strong&gt;storage fee&lt;/strong&gt;, which depends on the size of the data stored.&lt;/p&gt;

&lt;p&gt;In TON, data is stored in the &lt;strong&gt;&lt;code&gt;c4&lt;/code&gt;&lt;/strong&gt; register of TVM as a &lt;strong&gt;Cell&lt;/strong&gt;. Let’s briefly recall what a Cell is.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Cell is a data structure that can contain up to &lt;strong&gt;1023 bits&lt;/strong&gt; and &lt;strong&gt;4 references&lt;/strong&gt; to other cells.&lt;br&gt;
&lt;a href="https://docs.ton.org/v3/documentation/data-formats/tlb/cell-boc#cell" rel="noopener noreferrer"&gt;Read more: TON Documentation - Cell&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Cell is the fundamental building block of TVM.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Compute the Storage Size?
&lt;/h2&gt;

&lt;p&gt;According to the &lt;a href="https://docs.ton.org/v3/documentation/smart-contracts/func/docs/stdlib#computation-of-boc-size" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;, the FunC standard library provides the following functions to determine the size of a cell and a slice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;compute_data_size?&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;slice_compute_data_size?&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;compute_data_size&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;slice_compute_data_size&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s essential to understand &lt;strong&gt;how&lt;/strong&gt; the size is actually computed.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the description of the &lt;code&gt;compute_data_size?&lt;/code&gt; function:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Returns (x, y, z, -1) or (null, null, null, 0). It recursively calculates the number of &lt;strong&gt;unique cells&lt;/strong&gt; x, &lt;strong&gt;data bits&lt;/strong&gt; y, and &lt;strong&gt;cell references&lt;/strong&gt; z in the directed acyclic graph (DAG) at cell c. This provides the total storage used by the DAG while recognizing identical cells. "&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The key concepts here are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unique cells&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Identical cell recognition&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, what does “unique cells” mean? And how does the function recognize identical cells?&lt;/p&gt;

&lt;p&gt;Let’s explore this through research and practical tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project description
&lt;/h2&gt;

&lt;p&gt;To conduct this research, I created a project based on the &lt;a href="https://github.com/ton-org/blueprint" rel="noopener noreferrer"&gt;Blueprint template&lt;/a&gt;. You can find the project &lt;a href="https://github.com/a08778/ton-boc-size-analyzer" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: I won’t include source code here to keep the article clean and focused on the results.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The project includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A smart contract for computing storage size&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ton-org/sandbox" rel="noopener noreferrer"&gt;Sandbox&lt;/a&gt; tests&lt;/li&gt;
&lt;li&gt;A script for running production tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the tests, there are only tests for the &lt;code&gt;compute_data_size?&lt;/code&gt; and &lt;code&gt;slice_compute_data_size?&lt;/code&gt; functions because the only difference between these and their strict versions (&lt;code&gt;compute_data_size&lt;/code&gt;, &lt;code&gt;slice_compute_data_size&lt;/code&gt;) is that the strict versions raise an exception if the number of unique cells in the cell structure exceeds the &lt;code&gt;max_cells&lt;/code&gt; parameter passed to the functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;You need to have &lt;strong&gt;Node.js&lt;/strong&gt; installed to run the project locally. For an IDE, &lt;strong&gt;Visual Studio Code&lt;/strong&gt; is recommended, along with the &lt;strong&gt;FunC Language Support&lt;/strong&gt; plugin by Whales Corp, which can be found &lt;a href="https://marketplace.visualstudio.com/items?itemName=tonwhales.func-vscode" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart contact description
&lt;/h2&gt;

&lt;p&gt;The smart contract includes the following functionality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filling the storage with a custom Cell structure via an internal message with special opcode and custom cell data.&lt;/li&gt;
&lt;li&gt;Computing storage size using &lt;code&gt;compute_data_size?&lt;/code&gt; via the &lt;code&gt;get_results_for_cell&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Computing storage size using &lt;code&gt;slice_compute_data_size?&lt;/code&gt; via the &lt;code&gt;get_results_for_slice&lt;/code&gt; method.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The contract also computes the size of the input data during storage filling, verifying that computations on raw input data match those on stored internal data. This uses the &lt;code&gt;~dumb&lt;/code&gt; and &lt;code&gt;~strdump&lt;/code&gt; functions (&lt;a href="https://docs.ton.org/v3/documentation/smart-contracts/func/docs/stdlib#debug-primitives" rel="noopener noreferrer"&gt;debug primitives&lt;/a&gt;), and outputs can be seen when running Sandbox tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Cases &amp;amp; Observations
&lt;/h2&gt;

&lt;p&gt;To understand how &lt;code&gt;compute_data_size?&lt;/code&gt; and &lt;code&gt;slice_compute_data_size?&lt;/code&gt; behave under different scenarios, a variety of test cases were designed using custom cell structures. These tests aim to explore how the computation distinguishes between unique and identical cells, how data and references affect uniqueness, and how the &lt;code&gt;max_cells&lt;/code&gt; limit behaves. Each test case builds upon the previous one, gradually increasing in complexity and providing insights through both predictable and edge-case configurations.&lt;/p&gt;

&lt;h3&gt;
  
  
  An empty cell
&lt;/h3&gt;

&lt;p&gt;First of all, let's compute the size of an empty cell — a cell with no data and no references.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbzsnuloay1nxdakj2jip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbzsnuloay1nxdakj2jip.png" alt="The cell structure" width="349" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The functions return the following results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 1&lt;/li&gt;
&lt;li&gt;dataBits: 0&lt;/li&gt;
&lt;li&gt;references: 0&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing surprising. Let’s try to fill the cell with some data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not empty cell
&lt;/h3&gt;

&lt;p&gt;In this case, we fill the cell with some data and get the results again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeStringTail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsbgjd1nser8akq4bt96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsbgjd1nser8akq4bt96.png" alt="The cell structure" width="349" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the cell has 7 symbols of data, which is 56 bits in total (8 bits per symbol).&lt;/p&gt;

&lt;p&gt;The function returns the following results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 1&lt;/li&gt;
&lt;li&gt;dataBits: 56&lt;/li&gt;
&lt;li&gt;references: 0&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Again, the results are predictable. So how about references?&lt;/p&gt;

&lt;h3&gt;
  
  
  One reference
&lt;/h3&gt;

&lt;p&gt;Now we add one more cell to see the results for two cells.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpxsrkbccqt2cnarxlh2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpxsrkbccqt2cnarxlh2.png" alt="The cell structure" width="347" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have two cells with no data. The root cell refers to &lt;code&gt;cell_1&lt;/code&gt;. &lt;code&gt;cell_1&lt;/code&gt; has no references.&lt;/p&gt;

&lt;p&gt;This time we get the following results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 2&lt;/li&gt;
&lt;li&gt;dataBits: 0&lt;/li&gt;
&lt;li&gt;references: 1&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No surprises here. There is one reference from root to &lt;code&gt;cell_1&lt;/code&gt;, no data bits, and two cells total.&lt;/p&gt;

&lt;p&gt;Let’s make our cell structure a bit more complicated.&lt;/p&gt;

&lt;h3&gt;
  
  
  No references / no value
&lt;/h3&gt;

&lt;p&gt;In this case, we add a third cell which is identical to &lt;code&gt;cell_1&lt;/code&gt; (no data, no references) and observe how the functions work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flp2tbrf87hsbfmwg7z30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flp2tbrf87hsbfmwg7z30.png" alt="The cell structure" width="348" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We want to see how two identical cells (&lt;code&gt;cell_1&lt;/code&gt; and &lt;code&gt;cell_2&lt;/code&gt;) are treated when computing the size of the cell structure.&lt;/p&gt;

&lt;p&gt;Now we have the following results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 2&lt;/li&gt;
&lt;li&gt;dataBits: 0&lt;/li&gt;
&lt;li&gt;references: 2&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting part here is that we have only 2 unique cells. Therefore, we can make our first conclusion:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cells with no data and no references are treated as one unique cell.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  No references / the same value
&lt;/h3&gt;

&lt;p&gt;But how about the data? What results do we get if we have no empty cells? First let’s try with the same data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqainkteqtzvtedp1u755.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqainkteqtzvtedp1u755.png" alt="The cell structure" width="348" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cell_1&lt;/code&gt; and &lt;code&gt;cell_2&lt;/code&gt; now contain the same 1-bit uint value 0.&lt;/p&gt;

&lt;p&gt;After invoking functions, we get the results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 2&lt;/li&gt;
&lt;li&gt;dataBits: 1&lt;/li&gt;
&lt;li&gt;references: 2&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We see that &lt;code&gt;cell_1&lt;/code&gt; and &lt;code&gt;cell_2&lt;/code&gt; are again treated as one unique cell. Due to that, data bits are 1 and unique cells are 2.&lt;/p&gt;

&lt;p&gt;Our next conclusion is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cells with no references but with the same values are treated as one unique cell.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  No references / different values
&lt;/h3&gt;

&lt;p&gt;Logically, with different values, cells cannot be treated as identical. But programmers must verify hypotheses.&lt;/p&gt;

&lt;p&gt;Let’s fill &lt;code&gt;cell_1&lt;/code&gt; and &lt;code&gt;cell_2&lt;/code&gt; with different values this time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6zvejz9va1d91r4rk3om.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6zvejz9va1d91r4rk3om.png" alt="The cell structure" width="348" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cell_1&lt;/code&gt; has value 0, and &lt;code&gt;cell_2&lt;/code&gt; has value 1.&lt;/p&gt;

&lt;p&gt;After invoking functions, we get the results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 3&lt;/li&gt;
&lt;li&gt;dataBits: 2&lt;/li&gt;
&lt;li&gt;references: 2&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This time, all cells are treated as unique.&lt;/p&gt;

&lt;p&gt;We are done with no-reference cells. Let’s experiment with references.&lt;/p&gt;

&lt;h3&gt;
  
  
  References to the same cell
&lt;/h3&gt;

&lt;p&gt;We complicate our cell structure by adding a fourth cell. We want to understand how two cells with no value (or the same values) and references to the same cell are treated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;the_same_cell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;the_same_cell&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;the_same_cell&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4ncbnhbmhvdj715sh8y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4ncbnhbmhvdj715sh8y.png" alt="The cell structure" width="348" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After running functions, we get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 3&lt;/li&gt;
&lt;li&gt;dataBits: 0&lt;/li&gt;
&lt;li&gt;references: 3&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We see that &lt;code&gt;cell_1&lt;/code&gt; and &lt;code&gt;cell_2&lt;/code&gt; are treated as one unique cell. But there’s one more interesting thing: there are 3 references reported, although there are actually 4.&lt;/p&gt;

&lt;p&gt;It’s interesting because references to identical cells are counted normally, but references from cells treated as one unique cell are counted only once.&lt;/p&gt;

&lt;p&gt;We can conclude:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cells with no value or the same values that refer to the same cell are treated as one unique cell.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;References from cells treated as one unique cell are counted only once.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  References to identical cells
&lt;/h3&gt;

&lt;p&gt;With references to the same cell understood, how about references to identical cells? In this article, identical cells are synonymous with unique cells.&lt;/p&gt;

&lt;p&gt;Let’s add one more cell to see how it works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft02zqm1slgr6bnq4xbyl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft02zqm1slgr6bnq4xbyl.png" alt="The cell structure" width="348" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, &lt;code&gt;cell_1_1&lt;/code&gt; and &lt;code&gt;cell_2_1&lt;/code&gt; are basically one unique cell (no data / no references).&lt;/p&gt;

&lt;p&gt;The functions give the following results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 3&lt;/li&gt;
&lt;li&gt;dataBits: 0&lt;/li&gt;
&lt;li&gt;references: 3&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We see that &lt;code&gt;cell_1&lt;/code&gt; and &lt;code&gt;cell_2&lt;/code&gt; are treated as unique cells. &lt;code&gt;cell_1_1&lt;/code&gt; and &lt;code&gt;cell_2_1&lt;/code&gt; are also unique cells. All references from identical cells are counted only once, so two actual references (from &lt;code&gt;cell_1&lt;/code&gt; to &lt;code&gt;cell_1_1&lt;/code&gt; and from &lt;code&gt;cell_2&lt;/code&gt; to &lt;code&gt;cell_2_1&lt;/code&gt;) are counted as one reference.&lt;/p&gt;

&lt;p&gt;Our next conclusion:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cells with no data (or the same data) referring to identical cells are treated as one unique cell.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  References to non-identical cells
&lt;/h3&gt;

&lt;p&gt;To clarify that references to non-identical cells prevent treating our cells as unique, let’s check with code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fufsj57hvxepic6pjmwbw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fufsj57hvxepic6pjmwbw.png" alt="The cell structure" width="348" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This time, &lt;code&gt;cell_1_1&lt;/code&gt; and &lt;code&gt;cell_2_1&lt;/code&gt; contain different values.&lt;/p&gt;

&lt;p&gt;After invoking functions, we get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 5&lt;/li&gt;
&lt;li&gt;dataBits: 2&lt;/li&gt;
&lt;li&gt;references: 4&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All 5 cells are different. Q.E.D.&lt;/p&gt;

&lt;h3&gt;
  
  
  Different references order
&lt;/h3&gt;

&lt;p&gt;Now, we refer to identical cells, but the order of references is different. We use more than one reference per cell to check this, so our structure is more complex.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bottom_cell_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bottom_cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bottom_cell_2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bottom_cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bottom_cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bottom_cell_2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feq8mfbxigyyj643t5x8c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feq8mfbxigyyj643t5x8c.png" alt="The cell structure" width="347" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;cell_1&lt;/code&gt; and &lt;code&gt;cell_2&lt;/code&gt; refer to the same cells &lt;code&gt;bottom_cell_1&lt;/code&gt; and &lt;code&gt;bottom_cell_2&lt;/code&gt;, but in different orders:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cell_1.ref1&lt;/code&gt; --&amp;gt; &lt;code&gt;bottom_cell_1&lt;/code&gt;&lt;br&gt;
&lt;code&gt;cell_1.ref2&lt;/code&gt; --&amp;gt; &lt;code&gt;bottom_cell_2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cell_2.ref1&lt;/code&gt; --&amp;gt; &lt;code&gt;bottom_cell_2&lt;/code&gt;&lt;br&gt;
&lt;code&gt;cell_2.ref2&lt;/code&gt; --&amp;gt; &lt;code&gt;bottom_cell_1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After invoking functions, we get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 5&lt;/li&gt;
&lt;li&gt;dataBits: 1&lt;/li&gt;
&lt;li&gt;references: 6&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This leads to the conclusion:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If cells have the same data (or no data) and refer to the same cells, the order of references must be the same to treat them as one unique cell.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Identical structures except for the deepest level
&lt;/h3&gt;

&lt;p&gt;Let’s check a scenario where two branches of our structure are absolutely identical at all intermediate levels, but differ in the very last referenced cell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2_1_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1_1_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2_1_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1_1_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ybkn8114mljxvtwc96n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ybkn8114mljxvtwc96n.png" alt="The cell structure" width="348" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, &lt;code&gt;cell_1&lt;/code&gt; and &lt;code&gt;cell_2&lt;/code&gt; refer to cells that have no value and exactly one reference each. But the deepest cells they point to — &lt;code&gt;cell_1_1_1&lt;/code&gt; and &lt;code&gt;cell_2_1_1&lt;/code&gt; — are different because they contain different values.&lt;/p&gt;

&lt;p&gt;Results from &lt;code&gt;compute_data_size?&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 7&lt;/li&gt;
&lt;li&gt;dataBits: 2&lt;/li&gt;
&lt;li&gt;references: 6&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Observation:&lt;/strong&gt;&lt;br&gt;
Even though the structures above the leaves are visually identical, the difference at the bottom means that &lt;strong&gt;all cells in both branches are treated as unique&lt;/strong&gt;. This happens because uniqueness is checked recursively — if a referenced cell is different, its parent is automatically considered different, all the way up to the root.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;br&gt;
A difference at the deepest level propagates upward, making the entire branch unique in the computation.&lt;/p&gt;
&lt;h3&gt;
  
  
  Max cells limitation
&lt;/h3&gt;

&lt;p&gt;As a final test, let’s look at the behavior when &lt;code&gt;max_cells&lt;/code&gt; is limited to less than the actual number of cells.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffn6kikjvxoh2nfmxdmye.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffn6kikjvxoh2nfmxdmye.png" alt="The cell structure" width="348" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have 3 unique cells. Let’s set &lt;code&gt;max_cells&lt;/code&gt; parameter to 2 and see the results.&lt;/p&gt;

&lt;p&gt;The functions return:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: null&lt;/li&gt;
&lt;li&gt;dataBits: null&lt;/li&gt;
&lt;li&gt;references: null&lt;/li&gt;
&lt;li&gt;success: false&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the actual size of the cell structure exceeds &lt;code&gt;max_cells&lt;/code&gt;, we get nulls.&lt;/p&gt;

&lt;p&gt;But here we had 3 unique cells. How about 3 cells but only 2 unique ones?&lt;/p&gt;

&lt;h3&gt;
  
  
  Max cells limitation for actual / unique cells imbalance
&lt;/h3&gt;

&lt;p&gt;We again have 3 cells but only 2 unique ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cell_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;beginCell&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;storeRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell_2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;endCell&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjht0hu38b273bef8890s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjht0hu38b273bef8890s.png" alt="The cell structure" width="348" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The function invocation returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uniqueCells: 2&lt;/li&gt;
&lt;li&gt;dataBits: 0&lt;/li&gt;
&lt;li&gt;references: 2&lt;/li&gt;
&lt;li&gt;success: true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This lets us conclude:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;max_cells&lt;/code&gt; limits only the number of unique cells.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Production Tests
&lt;/h2&gt;

&lt;p&gt;The project includes a script (&lt;code&gt;testInProduction.ts&lt;/code&gt;) to run all tests on-chain.&lt;br&gt;
Results in production &lt;strong&gt;match&lt;/strong&gt; Sandbox results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Possible Improvements
&lt;/h2&gt;

&lt;p&gt;To reduce testing costs, modify the smart contract to &lt;strong&gt;return excess TON&lt;/strong&gt; after storage is filled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Conclusions
&lt;/h2&gt;

&lt;p&gt;The functions (&lt;code&gt;compute_data_size?&lt;/code&gt;, &lt;code&gt;slice_compute_data_size?&lt;/code&gt;,&lt;code&gt;compute_data_size&lt;/code&gt;,&lt;code&gt;slice_compute_data_size&lt;/code&gt;) calculate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unique cells&lt;/li&gt;
&lt;li&gt;Data bits&lt;/li&gt;
&lt;li&gt;References&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cells are &lt;strong&gt;identical&lt;/strong&gt; if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They have the same data (or none)&lt;/li&gt;
&lt;li&gt;Refer to identical cells&lt;/li&gt;
&lt;li&gt;Reference order is the same&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additional rules and nuances:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;References &lt;strong&gt;from&lt;/strong&gt; identical cells are &lt;strong&gt;counted once&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max_cells&lt;/code&gt; limits &lt;strong&gt;unique&lt;/strong&gt; cells only&lt;/li&gt;
&lt;li&gt;A difference in the deepest referenced cells propagates upward, making &lt;strong&gt;all parent cells along the branch unique&lt;/strong&gt;, even if intermediate cells have the same data and structure&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Afterword
&lt;/h2&gt;

&lt;p&gt;The test cases explored in this article helped demystify the behavior of &lt;code&gt;compute_data_size?&lt;/code&gt; and &lt;code&gt;slice_compute_data_size?&lt;/code&gt; in the TON Virtual Machine. By analyzing different cell configurations, the results provided a clear understanding of how data size is calculated, how identical cells are treated, and how reference structures influence outcomes.&lt;/p&gt;

&lt;p&gt;These insights are essential for developers aiming to optimize smart contract storage and cost in TON, ensuring both accuracy and efficiency in contract design.&lt;/p&gt;

</description>
      <category>tvm</category>
      <category>smartcontract</category>
      <category>func</category>
      <category>ton</category>
    </item>
  </channel>
</rss>
