> ## Documentation Index
> Fetch the complete documentation index at: https://companyname-a7d5b98e-ton-storage.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Using on-chain libraries

export const Aside = ({type = "note", title = "", icon = "", iconType = "regular", children}) => {
  const asideVariants = ["note", "tip", "caution", "danger"];
  const asideComponents = {
    note: {
      outerStyle: "border-sky-500/20 bg-sky-50/50 dark:border-sky-500/30 dark:bg-sky-500/10",
      innerStyle: "text-sky-900 dark:text-sky-200",
      calloutType: "note",
      icon: <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-sky-500" aria-label="Note">
          <path fill-rule="evenodd" clip-rule="evenodd" d="M7 1.3C10.14 1.3 12.7 3.86 12.7 7C12.7 10.14 10.14 12.7 7 12.7C5.48908 12.6974 4.0408 12.096 2.97241 11.0276C1.90403 9.9592 1.30264 8.51092 1.3 7C1.3 3.86 3.86 1.3 7 1.3ZM7 0C3.14 0 0 3.14 0 7C0 10.86 3.14 14 7 14C10.86 14 14 10.86 14 7C14 3.14 10.86 0 7 0ZM8 3H6V8H8V3ZM8 9H6V11H8V9Z"></path>
        </svg>
    },
    tip: {
      outerStyle: "border-emerald-500/20 bg-emerald-50/50 dark:border-emerald-500/30 dark:bg-emerald-500/10",
      innerStyle: "text-emerald-900 dark:text-emerald-200",
      calloutType: "tip",
      icon: <svg width="11" height="14" viewBox="0 0 11 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="text-emerald-600 dark:text-emerald-400/80 w-3.5 h-auto" aria-label="Tip">
          <path d="M3.12794 12.4232C3.12794 12.5954 3.1776 12.7634 3.27244 12.907L3.74114 13.6095C3.88471 13.8248 4.21067 14 4.46964 14H6.15606C6.41415 14 6.74017 13.825 6.88373 13.6095L7.3508 12.9073C7.43114 12.7859 7.49705 12.569 7.49705 12.4232L7.50055 11.3513H3.12521L3.12794 12.4232ZM5.31288 0C2.52414 0.00875889 0.5 2.26889 0.5 4.78826C0.5 6.00188 0.949566 7.10829 1.69119 7.95492C2.14321 8.47011 2.84901 9.54727 3.11919 10.4557C3.12005 10.4625 3.12175 10.4698 3.12261 10.4771H7.50342C7.50427 10.4698 7.50598 10.463 7.50684 10.4557C7.77688 9.54727 8.48281 8.47011 8.93484 7.95492C9.67728 7.13181 10.1258 6.02703 10.1258 4.78826C10.1258 2.15486 7.9709 0.000106649 5.31288 0ZM7.94902 7.11267C7.52078 7.60079 6.99082 8.37878 6.6077 9.18794H4.02051C3.63739 8.37878 3.10743 7.60079 2.67947 7.11294C2.11997 6.47551 1.8126 5.63599 1.8126 4.78826C1.8126 3.09829 3.12794 1.31944 5.28827 1.3126C7.2435 1.3126 8.81315 2.88226 8.81315 4.78826C8.81315 5.63599 8.50688 6.47551 7.94902 7.11267ZM4.87534 2.18767C3.66939 2.18767 2.68767 3.16939 2.68767 4.37534C2.68767 4.61719 2.88336 4.81288 3.12521 4.81288C3.36705 4.81288 3.56274 4.61599 3.56274 4.37534C3.56274 3.6515 4.1515 3.06274 4.87534 3.06274C5.11719 3.06274 5.31288 2.86727 5.31288 2.62548C5.31288 2.38369 5.11599 2.18767 4.87534 2.18767Z"></path>
        </svg>
    },
    caution: {
      outerStyle: "border-amber-500/20 bg-amber-50/50 dark:border-amber-500/30 dark:bg-amber-500/10",
      innerStyle: "text-amber-900 dark:text-amber-200",
      calloutType: "warning",
      icon: <svg className="flex-none w-5 h-5 text-amber-400 dark:text-amber-300/80" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-label="Warning">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
        </svg>
    },
    danger: {
      outerStyle: "border-red-500/20 bg-red-50/50 dark:border-red-500/30 dark:bg-red-500/10",
      innerStyle: "text-red-900 dark:text-red-200",
      calloutType: "danger",
      icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" className="text-red-600 dark:text-red-400/80 w-4 h-4" aria-label="Danger">
          <path d="M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zm41.6-48c-4.3 7.4-4.3 16.6 0 24l88.3 152.9c4.3 7.4 12.2 12 20.8 12l176.6 0c8.6 0 16.5-4.6 20.8-12L453.4 268c4.3-7.4 4.3-16.6 0-24L365.1 91.1c-4.3-7.4-12.2-12-20.8-12l-176.6 0c-8.6 0-16.5 4.6-20.8 12L58.6 244zM256 128c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"></path>
        </svg>
    }
  };
  let variant = type;
  let gotInvalidVariant = false;
  if (!asideVariants.includes(type)) {
    gotInvalidVariant = true;
    variant = "danger";
  }
  const iconVariants = ["regular", "solid", "light", "thin", "sharp-solid", "duotone", "brands"];
  if (!iconVariants.includes(iconType)) {
    iconType = "regular";
  }
  return <>
      <div className={`callout my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border ${asideComponents[variant].outerStyle}`} data-callout-type={asideComponents[variant].calloutType}>
        <div className="mt-0.5 w-4" data-component-part="callout-icon">
          {}
          {icon === "" ? asideComponents[variant].icon : <Icon icon={icon} iconType={iconType} size={14} />}
        </div>
        <div className={`text-sm prose min-w-0 w-full ${asideComponents[variant].innerStyle}`} data-component-part="callout-content">
          {gotInvalidVariant ? <p>
              <span className="font-bold">
                Invalid <code>type</code> passed!
              </span>
              <br />
              <span className="font-bold">Received: </span>
              {type}
              <br />
              <span className="font-bold">Expected one of: </span>
              {asideVariants.join(", ")}
            </p> : <>
              {title && <p className="font-bold">{title}</p>}
              {children}
            </>}
        </div>
      </div>
    </>;
};

export const Image = ({src, darkSrc, alt = "", darkAlt, href, target, height = 342, width = 608}) => {
  const isSVG = src.match(/\.svg(?:[#?].*?)?$/i) !== null;
  const shouldInvert = isSVG && !darkSrc;
  const shouldCreateLink = href !== undefined;
  const minPx = 9;
  const maxPx = 608;
  const expectedPx = `a number or a string with a number that is greater than ${minPx - 1} and less than or equal to ${maxPx}`;
  const createInvalidPropCallout = (title, received, expected) => {
    return <Danger>
        <span className="font-bold">
          Invalid <code>{title.toString()}</code> passed!
        </span>
        <br />
        <span className="font-bold">Received: </span>
        {received.toString()}
        <br />
        <span className="font-bold">Expected: </span>
        {expected.toString()}
        {}
      </Danger>;
  };
  const checkValidDimensionValue = value => {
    switch (typeof value) {
      case "string":
      case "number":
        const num = Number(value);
        return Number.isSafeInteger(num) && num >= minPx && num <= maxPx;
      default:
        return false;
    }
  };
  let callouts = [];
  if (height && !checkValidDimensionValue(height)) {
    callouts.push(createInvalidPropCallout("height", height, expectedPx));
  }
  if (width && !checkValidDimensionValue(width)) {
    callouts.push(createInvalidPropCallout("width", width, expectedPx));
  }
  if (callouts.length !== 0) {
    return callouts;
  }
  const heightPx = Number(height);
  const widthPx = Number(width);
  const images = <>
      <img className="block dark:hidden" src={src} alt={alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert) && ({
    noZoom: "true"
  })} />
      <img className={`hidden dark:block ${shouldInvert ? "invert" : ""}`} src={darkSrc ?? src} alt={darkAlt ?? alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert) && ({
    noZoom: "true"
  })} />
    </>;
  if (shouldCreateLink) {
    return <a href={href} target={target ?? "_self"}>
        {images}
      </a>;
  }
  return images;
};

It is recommended to read [Library cells](/foundations/serialization/library) first.

<Aside type="danger">
  You should always monitor the balance of the account that hosts the library. It should be sufficient for at least 10 years.
</Aside>

### Fee savings

Library cells help reduce fees in two main ways.

1. Forwarding fees. For example, in [jettons](/standard/tokens/jettons/overview), the [`StateInit`](/foundations/messages/deploy) must be forwarded with each transfer, resulting in high forwarding fees. Moving the code into a library cell significantly reduces these fees.

2. Storage costs. Because a library must be hosted in the Masterchain, where storage is approximately 1,000 times more expensive than in the Basechain, hosting a copy of the code in the Basechain may be cheaper if there are fewer than 1,000 instances of the contract. The 1,000 factor is not constant and is subject to change. Consult [blockchain config parameter 18](https://tonviewer.com/config#18) for the latest value. However, due to the savings on forwarding fees, you should calculate whether this approach is cost-effective for your specific use case.

Everything in TON is stored in cells, even the account code. One of the most common use cases for libraries is to store code shared by multiple contracts.
When a library cell is part of an account’s `code`, it is automatically dereferenced on first access. This allows you to replace part of the contract code—or even the entire code—with a library cell.

Replacing the entire code with a library cell is widely used in TON smart contracts.
Some common examples:

1. USDT (and other popular jettons) Jetton wallet contracts
2. The Order contract in Multisig v2
3. NFT item contracts in popular collections

You can check if a contract is using a library as its code by looking into its `code` cell in an explorer.

```txt title="Fragment of USDT jetton-wallet account" theme={null}
...
code:(just
      value:(raw@^Cell
        x{}
         SPECIAL x{028F452D7A4DFD74066B682365177259ED05734435BE76B5FD4BD5D8AF2B7C3D68}
        ))
...
```

While it is not crucial to understand the exact representation shown on the [TON Explorer](https://explorer.toncoin.org/) ([more about explorers](/ecosystem/explorers/overview)), the key point is that there is only one cell in the contract code, tagged as `SPECIAL`, indicating it is an exotic cell. Following this is the hexadecimal representation of the library cell's internals. The first byte equals 2, indicating that it is a library cell, and the remaining bytes contain the hash of the referenced cell.

Here you can see that the entire contract code consists of the 8-bit tag equal to 2 and a 256-bit representation hash of the referenced cell.

If you don’t want to put the entire code in a library cell, you can make only part of it a library cell. For example, if the same function is used in multiple different contracts, it makes sense to turn it into a library. However, you will likely need to set up the build process for such code yourself.

### Using @ton/core

You can construct a library cell entirely in TypeScript using the `@ton/core` library. Here’s how to do it in a Blueprint project:

```ts theme={null}
import { Cell, beginCell } from '@ton/core';

const libPrep = beginCell().storeUint(2, 8).storeBuffer(jwalletCodeRaw.hash()).endCell();
const jwalletCode = new Cell({ exotic: true, bits: libPrep.bits, refs: libPrep.refs });
```

* [View source](https://github.com/ton-blockchain/stablecoin-contract/blob/de08b905214eb253d27009db6a124fd1feadbf72/sandbox_tests/JettonWallet.spec.ts#L104C1-L105C90)

### Publishing an ordinary cell in the Masterchain library context

The following example was taken from [multisig v2 repository](https://github.com/ton-blockchain/multisig-contract-v2/blob/master/contracts/helper/librarian.func).

```func theme={null}
;; Simple library keeper

#include "../imports/stdlib.fc";
#include "../messages.func";

const int DEFAULT_DURATION = 3600 * 24 * 365 * 10; ;; 10 years, can top-up in any time
const int ONE_TON = 1000000000;

;; https://docs.ton.org/tvm.pdf, page 138, SETLIBCODE
() set_lib_code(cell code, int mode) impure asm "SETLIBCODE";

cell empty_cell() asm "<b b> PUSHREF";

() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure {
    slice in_msg_full_slice = in_msg_full.begin_parse();
    int msg_flags = in_msg_full_slice~load_msg_flags();
    slice sender_address = in_msg_full_slice~load_msg_addr();

    cell lib_to_publish = get_data();

    int initial_gas = gas_consumed();
    (int order_cells, int order_bits, _) = compute_data_size(lib_to_publish, 1000); ;; according network config, max cells in library = 1000
    int size_counting_gas = gas_consumed() - initial_gas;

    int to_reserve = get_simple_compute_fee(MASTERCHAIN, size_counting_gas) +
                     get_storage_fee(MASTERCHAIN, DEFAULT_DURATION, order_bits, order_cells);
    raw_reserve(to_reserve, RESERVE_BOUNCE_ON_ACTION_FAIL);

    send_message_with_only_body(sender_address, 0, begin_cell(), NON_BOUNCEABLE, SEND_MODE_CARRY_ALL_BALANCE);
    ;; https://docs.ton.org/tvm.pdf, page 138, SETLIBCODE
    set_lib_code(lib_to_publish, 2); ;; if x = 2, the library is added as a public library (and becomes available to all smart contracts if the current smart contract resides in the masterchain);
    ;; brick contract
    set_code(empty_cell());
    set_data(empty_cell());
}
```

The main benefit of using this contract to publish library cells is that it requires you to provide sufficient TON for at least 10 years of storage. This prevents a common problem where, after a short time, the library freezes and becomes inaccessible, which can lead to unexpected scenarios.

The core of this contract is the line: `set_lib_code(lib_to_publish, 2);`. This function call publishes an ordinary cell with the flag set to `2`, which indicates that the library is public and can be used by anyone.

Note that this contract becomes bricked after the cell is published, so no further operations on this contract can be performed.

### Testing in Blueprint

When testing smart contracts locally, there are **two ways to register libraries** in your blockchain environment.

#### Option 1: **Automatic Library Deployment**

Enable automatic library detection by passing the `autoDeployLibs` flag when creating the blockchain:

```ts theme={null}
const blockchain = await Blockchain.create({ autoDeployLibs: true });
```

In your contract, deployed in **Masterchain**, deploy the library using the librarian example above.

This allows the contract to dynamically install and register the library at runtime, with the environment automatically tracking and using it as needed.

#### Option 2: **Manual Library Deployment**

If `autoDeployLibs` is **not enabled**, you'll need to register libraries manually:

```ts theme={null}
const blockchain = await Blockchain.create();
const code = await compile('Contract');

// Create a dictionary of library hash → library cell
const libsDict = Dictionary.empty(Dictionary.Keys.Buffer(32), Dictionary.Values.Cell());
libsDict.set(code.hash(), code);

// Manually assign the libraries
blockchain.libs = beginCell().storeDictDirect(libsDict).endCell();
```

This gives you full control but requires explicitly managing which libraries are available during testing.

An example implementation can be found [here](https://github.com/ton-blockchain/stablecoin-contract/blob/de08b905214eb253d27009db6a124fd1feadbf72/sandbox_tests/JettonWallet.spec.ts#L100C9-L103C32).

### Get methods for library-cell-based contracts

When working with a Jetton wallet where the code is stored in a library cell, you may need to check its balance. To do so, you must execute a get method in the code.

If you call methods using one of [HTTP APIs](/ecosystem/api/overview) or [LiteServer](/ecosystem/node/overview), the library cell will be automatically resolved and the method will be executed.

Alternatively, take the account state to your local system and execute methods there.
In that case, you will need to pull the account state and resolve all library reference cells (in most cases, if the contract is using libraries, the whole code of the contract is a library reference).
To resolve a library, the only thing you need is to call [getLibraries method](/ecosystem/api/toncenter/v2/blocks/get-smart-contract-libraries)

#### Retrieving a library cell with LiteServer

To retrieve library cells from LiteServer, use the [liteServer.getLibraries](https://github.com/ton-blockchain/ton/blob/4cfe1d1a96acf956e28e2bbc696a143489e23631/tl/generate/scheme/lite_api.tl#L96) method.

```ts theme={null}
import { LiteClient, LiteRoundRobinEngine, LiteSingleEngine } from "ton-lite-client";
import { Cell } from "@ton/core";
import { z } from "zod";

function intToIP(int: number): string {
    const buf = Buffer.alloc(4);
    buf.writeUInt32BE(int >>> 0, 0);
    return Array.from(buf).join(".");
}

const Server = z.object({
    ip: z.number(),
    port: z.number(),
    id: z.object({ key: z.string() }),
});

const Response = z.object({
    liteservers: z.array(Server),
});

// testnet https://ton.org/testnet-global.config.json
// mainnet https://ton.org/global.config.json
const configEndpoint = "https://ton.org/global.config.json";

async function getServers() {
    const data = Response.parse(await (await fetch(configEndpoint)).json());
    return data.liteservers.map((server) => {
        return new LiteSingleEngine({
            host: `tcp://${intToIP(server.ip)}:${server.port}`,
            publicKey: Buffer.from(server.id.key, 'base64'),
        });
    });
}

async function getLibraryByHash(hash: Buffer) {
    const engine = new LiteRoundRobinEngine(await getServers());
    const client = new LiteClient({ engine });
    const libs = await client.getLibraries([hash]);
    const lib = libs.result[0];
    if (!lib || libs.result.length !== 1) {
        throw new Error("Library not found");
    }
    const roots = Cell.fromBoc(lib.data);
    const root = roots[0];
    if (!root || roots.length !== 1) {
        throw new Error("Malformed BoC for a library");
    }
    return root.toBoc().toString("hex");
}

async function main() {
    const hash = Buffer.from("8F452D7A4DFD74066B682365177259ED05734435BE76B5FD4BD5D8AF2B7C3D68", "hex");
    const code = await getLibraryByHash(hash);
    console.log(code);
}

void main();
```
