Use library cells when multiple contracts share the same code and forwarding or storage costs need to be reduced, resulting in fee savings.For example, in jettons, the StateInit must be forwarded with each transfer, which increases forwarding fees. Moving the code into a library cell reduces that overhead.However, a library must be hosted in the masterchain, where storage is more expensive than in the basechain. If fewer than about 1,000 contracts share the same code, storing a copy in the basechain can be cheaper.The exact ratio depends on blockchain config parameter 18. Compare storage and forwarding costs before choosing this approach.
Everything in TON is stored in cells, including the account code. A common use case for libraries is shared code across multiple contracts. When a library cell is part of an account’s code, the runtime dereferences it on first access. This makes it possible 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 used in TON smart contracts. Examples include:
Check whether a contract uses a library as its code by inspecting its code cell in an explorer.
Partial explorer snippet of a USDT jetton wallet account
...code:(just value:(raw@^Cell x{} SPECIAL x{028F452D7A4DFD74066B682365177259ED05734435BE76B5FD4BD5D8AF2B7C3D68} ))...
The exact representation in the TON Explorer is not important. The key point is that the contract code contains a single SPECIAL cell, which indicates an exotic cell. The first byte equals 2, which marks a library cell. The remaining bytes contain the hash of the referenced cell.In this form, the entire contract code consists of the 8-bit tag 2 and the 256-bit representation hash of the referenced cell.If only part of the code should live in a library cell, move the shared function into a library instead. This approach is used when multiple contracts reuse the same function. The build process for this setup may require custom tooling.
Publish an ordinary cell in the masterchain library context
The following Tolk example is based on the librarian contract from the multisig v2 repository.
import "@stdlib/gas-payments"const DEFAULT_DURATION = 3600 * 24 * 365 * 10 // 10 years, can top-up in any timeconst ONE_TON = ton("1")// https://docs.ton.org/tvm/instructions#fb06-setlibcodefun setLibCode(code: cell, mode: int): void asm "SETLIBCODE"fun emptyCell(): cell asm "<b b> PUSHREF"fun onInternalMessage(in: InMessage) { val senderAddress = in.senderAddress; val libToPublish = contract.getData(); val initialGas = getGasConsumedAtTheMoment(); val (orderCells, orderBits, _) = libToPublish.calculateSizeStrict(1000); val sizeCountingGas = getGasConsumedAtTheMoment() - initialGas; val toReserve = calculateGasFeeWithoutFlatPrice(-1, sizeCountingGas) + calculateStorageFee(-1, DEFAULT_DURATION, orderBits, orderCells); reserveToncoinsOnBalance(toReserve, RESERVE_MODE_BOUNCE_ON_ACTION_FAIL); val reply = createMessage({ bounce: BounceMode.NoBounce, dest: senderAddress, value: 0 }); reply.send(SEND_MODE_CARRY_ALL_BALANCE); setLibCode(libToPublish, 2); contract.setCodePostponed(emptyCell()); contract.setData(emptyCell());}
This contract requires enough TON for at least 10 years of storage. That prevents the library from freezing shortly after publication and becoming inaccessible.The key line is setLibCode(libToPublish, 2);. This call publishes an ordinary cell with the flag set to 2, which makes the library public.
For contracts deployed in the masterchain, publish the library with the librarian example above.This lets the contract install and register the library at runtime, while the environment tracks and uses it automatically.
If autoDeployLibs is not enabled, register libraries manually:
const blockchain = await Blockchain.create();const code = await compile('Contract');// Create a dictionary of library hash → library cellconst libsDict = Dictionary.empty(Dictionary.Keys.Buffer(32), Dictionary.Values.Cell());libsDict.set(code.hash(), code);// Manually assign the librariesblockchain.libs = beginCell().storeDictDirect(libsDict).endCell();
This approach gives full control, but it requires explicit management of the libraries available during testing.Reference implementation: JettonWallet.spec.ts.
When working with a jetton wallet whose code is stored in a library cell, check its balance by executing a get method.When methods run through the HTTP API or liteserver, the library cell is resolved automatically and the method runs against the resolved code.For local execution, pull the account state and resolve every library reference cell first. In most cases, the entire code cell is itself a library reference.
To resolve a library, call the /getLibraries method.