> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ton.org/llms.txt
> Use this file to discover all available pages before exploring further.

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.ton.org/feedback

```json
{
  "path": "/foundations/status",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Account status

export const Image = ({src, darkSrc, alt = '', darkAlt, href, target, height = 342, width = 608, noZoom = false, center = false}) => {
  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 shouldCenter = center === "true" || center === true ? true : false;
  const shouldNotZoom = noZoom === "true" || noZoom === true ? true : false;
  const images = <>
      <img className="block dark:hidden" src={src} alt={alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert || shouldNotZoom) && ({
    noZoom: "true"
  })} />
      <img className={`hidden dark:block ${shouldInvert ? "invert" : ""}`} src={darkSrc ?? src} alt={darkAlt ?? alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert || shouldNotZoom) && ({
    noZoom: "true"
  })} />
    </>;
  if (shouldCreateLink) {
    if (shouldCenter) {
      return <div style={{
        display: "flex",
        justifyContent: "center"
      }}>
          <a href={href} target={target ?? "_self"}>
            {images}
          </a>
        </div>;
    }
    return <a href={href} target={target ?? "_self"}>
        {images}
      </a>;
  }
  if (shouldCenter) {
    return <div style={{
      display: "flex",
      justifyContent: "center"
    }}>{images}</div>;
  }
  return images;
};

This article describes the four possible states of an account on TON Blockchain.
Understanding these states is crucial for accurately predicting transaction outcomes and ensuring the correct deployment.

## What is the account status?

The account status is a formal indicator of what actions can occur with an account, what it can store, and whether it contains a contract code. In other words, it is one of the main factors determining the behavior of a given account during a transaction. The account status at the beginning and end of a transaction is recorded in [the corresponding TL-B block](https://github.com/ton-blockchain/ton/blob/cac968f77dfa5a14e63db40190bda549f0eaf746/crypto/block/block.tlb#L285) in the fields `orig_status` and `end_status`. Thus, it allows developers to always view the current status of an account before sending it a message and restore the history of its status changes.

## Status variety

Each account exists in one of the following statuses:

* **nonexist**: the default status for accounts with no transaction history or that were deleted. Contains no code, data, or balance. All 2<sup>256</sup> accounts start in this status.
* **uninit**: holds a balance and metadata, but no code and persistent data. It cannot execute logic but retains funds (and accumulates the storage fee) until the contract code is deployed.
* **active**: contains code, data, and a balance. Fully deployed and operational, capable of processing messages.
* **frozen**: occurs when the storage debt of an active account exceeds 0.1 TON. Only the hashes of the previous code and data cells are preserved. While frozen, the contract cannot be executed. To unfreeze, send a message with the valid [`StateInit`](/foundations/messages/deploy) and sufficient funds for storage fees. Recovery is complex; avoid reaching this state. A project to unfreeze accounts is available [here](https://unfreezer.ton.org/).

### Why exactly these four statuses?

Although the need for the `active` and `nonexist` statuses is obvious, the purpose of the `uninit` and `frozen` statuses is not immediately clear.

**`nonexist` vs `uninit`**:

As was mentioned above, each account starts in the `nonexist` status. Besides code and persistent data, in this status, an account also has no [metadata](https://github.com/ton-blockchain/ton/blob/cac968f77dfa5a14e63db40190bda549f0eaf746/crypto/block/block.tlb#L258), so it does not accumulate the storage fee. At the same time, the `uninit` status of an account indicates that some actions were performed with it and, possibly, it is prepared for deployment. So, the `uninit` account always has a [positive balance and some additional information](https://github.com/ton-blockchain/ton/blob/cac968f77dfa5a14e63db40190bda549f0eaf746/crypto/block/block.tlb#L259-L260) for which it must pay a storage fee.

Sending an internal message with a valid `state_init` and proper `value` to `nonexist` account results in its deployment and the status changes to `active`. The key point is that the deployment occurs during the compute phase, which requires a suitable number of nanotons to run. But often you want to be able to deploy an account through an **external message**, to which you can also attach `state_init`, but it is impossible to attach `value`! This is also the purpose for which `uninit` exists. You can initially transfer the balance to the account via an internal message, notifying the rest of the blockchain participants of your intention to deploy an account in the future. And only then, including through an external message, to deploy.

**`frozen` vs `uninit`**:

When the active account's storage debt exceeds 0.1 TON, it becomes `frozen` or `uninit`. It is possible to restore the account from these statuses by paying off the debt and attaching `state_init`. If the account code and its persistent data have not changed during the lifetime of the account, then there is no problem restoring it from `uninit`. But what if they have changed? Since the `uninit` status does not allow you to store any information about the account's history, its last state will be lost forever. To prevent such situations, the `frozen` status exists.

The main difference between the `uninit` and `frozen` statuses is that in addition to metadata, the `frozen` account contains hash of the [last account state](https://github.com/ton-blockchain/ton/blob/cac968f77dfa5a14e63db40190bda549f0eaf746/crypto/block/block.tlb#L268). Thus, it becomes possible to restore the last state of an account before it was frozen by sending a `state_nint` to it, whose hash matches the one recorded on the account.

## Status transitions

We present here a diagram that describes all potential changes in the account status during the receipt of internal or external messages.

### Diagram

In the diagram below, there are four nodes representing the four different account statuses. Each arrow and loop corresponds to a change in the account status at the end of a given transaction. The parameters in the blocks above the arrows (and loops) briefly describe what caused the transaction and also contain some fields that affect the change in the account status.

<Image src="/resources/images/statuses-light.svg" darkSrc="/resources/images/statuses-dark.svg" alt="Status changes diagram" />

So, let's look at what changes can occur to a `nonexist` account depending on the messages that come to it.

* **Receiving external messages**: no changes.
* **Receiving internal messages**:
  * **With a valid `state_init` and sufficient value**: the contract is deployed on its address that becomes `active` before processing the message.
  * **Without/with invalid `state_init` or with insufficient value**: if the message is **bounceable**, then it returns to the sender, and the account status isn't changed. Otherwise, with no `value` in the message, the account status isn't changed. Finally, it becomes `uninit` if it received a valid `state_init` but insufficient nanotons or if `state_init` is absent or invalid.

With the diagram **Legend** below, you can inspect all possible changes in the account status when receiving messages with different parameters.

### Legend

* `type`: message type.
  * any;
  * internal;
  * external;
* `bounce`: `bounce` flag of an internal message.
  * any;
  * true;
  * false;
* `value`: an amount of nanotons in a message.
  * any;
  * 0;
  * \> 0.
* `state_init`: [`StateInit`](/foundations/messages/deploy) structure.
  * any;
  * none;
  * invalid: the address computed from a given `state_init` does not match the recipient address;
  * valid: the computed address matches a recipient address;
  * valid last state: must be `state_init` of the last successful transaction before the account becomes frozen.
* `balance`: The account balance in nanotons after **Storage phase** of the transaction.
  * 0;
  * \> 0;
  * \< 40000;
  * \>= 40000;
  * (0, 40000).
* `storage_fees_due`: the number of storage fees that were charged but could not be collected. In the diagram, this field indicates `storage_fees_due` after the **Storage phase**.
  * 0;
  * \< 0.1;
  * \< 1;
  * \>= 0.1;
  * \>= 1.
* `send_dest_if_zero`: is there any outgoing message with flag 32 in **Action phase**?
  * any;
  * false;
  * true;
  * invalid: there was no **Action phase**.
* `zero_bal_after_dest_act`: Whether the account balance became zero when sending some of the messages with the flag 32. This field is meaningful only if there's at least one such message during **Action phase**.
  * any;
  * false;
  * true.
* `action_phase_is_successful`: was **Action phase** successful?
  * false;
  * true.
* `account_state_changed`: has the account's state changed during its lifetime?
  * false;
  * true.

### Key points

We additionally review some important points regarding the statuses except `nonexist`.

**Sending to `uninit` account**:

* **Messages of any type without `state_init`**: changes to `nonexist` if its balance becomes zero.
* **Messages of any type with valid `state_init`**: changes to `active` if the balance is at least 40000 nanotons.

**Sending to `frozen` account**:

* **Messages of any type**: Changes to `nonexist` if its `storage_fees_due` exceeds 1 TON and the balance is zero.
* **Internal message with valid `state_init` (non-bounceable)**: changes to `active` if its `storage_fees_due` becomes zero.
* **Internal message with valid `state_init` (bounceable)**: changes to `active` with the same debt, and the account balance equals the message's balance minus compute and action fees.

**Sending to `active` account**:

* **Messages of any type**: changes to `frozen` if its `storage_fees_due` exceeds 0.1 TON and the account's state has ever changed.
* **Messages of any type**: changes to `uninit` if its `storage_fees_due` exceeds 0.1 TON and the account's state has never changed.
* **Messages of any type**: if in the action list there is an outgoing message with the flag 32 but **Action phase** was unsuccessful or the balance after this action is positive, the account status doesn't change.
* **Messages of any type with any `state_init`**: new `state_init` will be ignored and therefore doesn't change the account status.

**Deployment strategy**: The standard practice for deploying a wallet is to first send a non-bounceable message with Toncoin to its address. This transitions the account to the `uninit` status. The wallet owner can then deploy the contract in a subsequent transaction, using the pre-funded balance.

**Protection against errors**: standard wallets and applications manage these complexities by automatically setting the `bounce` flag based on the status of the destination account. Developers of custom applications must implement similar logic to prevent fund loss.

## Summary

* The account status (`nonexist`, `uninit`, `active`, `frozen`) defines behavior.
* Correct handling of `state_init` and the `bounce` flag is crucial for successful deployment and avoiding unintended fund transfers.
* There are many cases when the account status can become `nonexist` or `frozen`. Keep track of the amount of TON on the account balance!
* Each new `state_init` is ignored when the account status is active.
