> ## Documentation Index
> Fetch the complete documentation index at: https://neardocs-update-rpc-openapi.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# State

> Explore how NEAR smart contracts manage their state.

export const File = ({children}) => {
  return children;
};

export const Block = ({children}) => {
  return children;
};

export const ExplainCode = ({children}) => {
  const [activeBlock, setActiveBlock] = useState(0);
  const [code, setCode] = useState(null);
  const blockRefs = useRef({});
  const codeContainerRef = useRef(null);
  const ratioMap = useRef({});
  function toRaw(ref) {
    const fullUrl = ref.slice(ref.indexOf('https'));
    const [url] = fullUrl.split('#');
    const [org, repo, , branch, ...pathSeg] = new URL(url).pathname.split('/').slice(1);
    return `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${pathSeg.join('/')}`;
  }
  async function fetchRaw(url, fromLine, toLine) {
    let res;
    if (typeof window !== 'undefined') {
      const validUntil = localStorage.getItem(`${url}-until`);
      if (validUntil && Number(validUntil) > Date.now()) {
        res = localStorage.getItem(url);
      }
    }
    if (!res) {
      try {
        res = await (await fetch(url)).text();
        if (typeof window !== 'undefined') {
          localStorage.setItem(url, res);
          localStorage.setItem(`${url}-until`, String(Date.now() + 60000));
        }
      } catch {
        return 'Error fetching code, please try reloading';
      }
    }
    let lines = res.split('\n');
    const from = fromLine ? Number(fromLine) - 1 : 0;
    const to = toLine ? Number(toLine) : lines.length;
    lines = lines.slice(from, to);
    const indent = lines.reduce((prev, line) => {
      if (!line.length) return prev;
      const m = line.match(/^\s+/);
      return m ? Math.min(prev, m[0].length) : 0;
    }, Infinity);
    return lines.map(l => l.slice(indent === Infinity ? 0 : indent)).join('\n');
  }
  function parseHighlights(str) {
    const set = new Set();
    if (!str) return set;
    String(str).split(',').forEach(part => {
      const [a, b] = part.trim().split('-');
      if (b) {
        for (let i = Number(a); i <= Number(b); i++) set.add(i);
      } else if (a) set.add(Number(a));
    });
    return set;
  }
  const blocks = [];
  const files = [];
  function collect(node) {
    if (!node) return;
    if (Array.isArray(node)) {
      node.forEach(collect);
      return;
    }
    if (typeof node !== 'object' || !node.props) return;
    if (node.props.url !== undefined) {
      files.push({
        ...node.props
      });
    } else if (node.type === Block || node.props.fname !== undefined) {
      blocks.push({
        text: node.props.children,
        highlight: node.props.highlights,
        fname: node.props.fname,
        type: node.props.type
      });
    } else {
      collect(node.props.children);
    }
  }
  collect(children);
  const activeFname = blocks[activeBlock]?.fname || files[0]?.fname;
  const fileKey = activeFname;
  const currentFile = files.find(f => f.fname === activeFname) || files[0];
  useEffect(() => {
    const observedEls = Object.entries(blockRefs.current).filter(([, el]) => el);
    const observer = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        const idx = Number(entry.target.dataset.blockIdx);
        ratioMap.current[idx] = entry.intersectionRatio;
      });
      let bestIdx = -1;
      let bestRatio = 0;
      Object.entries(ratioMap.current).forEach(([idx, ratio]) => {
        if (ratio > bestRatio) {
          bestRatio = ratio;
          bestIdx = Number(idx);
        }
      });
      if (bestIdx !== -1) {
        setActiveBlock(bestIdx);
      } else {
        const zoneTop = window.innerHeight * 0.2;
        const allAboveZone = Object.entries(blockRefs.current).filter(([, el]) => el).every(([, el]) => el.getBoundingClientRect().bottom < zoneTop);
        if (allAboveZone) setActiveBlock(-1);
      }
    }, {
      threshold: [0, 0.1, 0.25, 0.5, 0.75, 1],
      rootMargin: '-20% 0px -50% 0px'
    });
    observedEls.forEach(([idx, el]) => {
      el.dataset.blockIdx = idx;
      observer.observe(el);
    });
    return () => observer.disconnect();
  }, [blocks.length]);
  useEffect(() => {
    if (!currentFile?.url) return;
    setCode(null);
    const rawUrl = toRaw(currentFile.url);
    fetchRaw(rawUrl, currentFile.start, currentFile.end).then(setCode);
  }, [fileKey]);
  const highlighted = parseHighlights(blocks[activeBlock]?.highlight);
  const firstHighlightedLine = highlighted.size > 0 ? Math.min(...highlighted) : null;
  useEffect(() => {
    const container = codeContainerRef.current;
    if (!container || code === null || firstHighlightedLine === null) return;
    const frame = requestAnimationFrame(() => {
      const highlightedLine = container.querySelector(`[data-line="${firstHighlightedLine}"], [data-line-number="${firstHighlightedLine}"], pre code > span:nth-child(${firstHighlightedLine})`);
      if (highlightedLine) {
        const offset = highlightedLine.getBoundingClientRect().top - container.getBoundingClientRect().top;
        container.scrollTo({
          top: Math.max(0, container.scrollTop + offset - container.clientHeight / 2 + highlightedLine.clientHeight / 2),
          behavior: 'smooth'
        });
        return;
      }
      const codeElement = container.querySelector('pre code');
      const lineHeight = codeElement ? Number.parseFloat(getComputedStyle(codeElement).lineHeight) : 0;
      container.scrollTo({
        top: Math.max(0, (firstHighlightedLine - 2) * (lineHeight || 24)),
        behavior: 'smooth'
      });
    });
    return () => cancelAnimationFrame(frame);
  }, [activeBlock, code, firstHighlightedLine]);
  return <div className="my-6 not-prose">
      {}
      <div className="flex gap-8 items-start">
        {}
        <div className="flex-[5] flex flex-col gap-3 min-w-0 pb-[40vh]">
          {blocks.map((block, i) => block.type ? <div key={i} ref={el => {
    blockRefs.current[i] = el;
  }}>
              {block.text}
            </div> : <div key={i} ref={el => {
    blockRefs.current[i] = el;
  }} onClick={() => setActiveBlock(i)} className={['cursor-pointer rounded-md px-5 py-4 transition-all duration-200 border-l-4 border-indigo-500', activeBlock === i ? 'shadow-sm' : 'opacity-60 hover:opacity-90'].join(' ')} style={{
    backgroundColor: activeBlock === i ? 'var(--explain-card-active-bg)' : 'var(--explain-card-bg)',
    border: activeBlock === i ? '1px solid var(--explain-card-border)' : '1px solid transparent'
  }}>
              {block.text}
            </div>)}
        </div>

        {}
        {currentFile && <div className="flex-[6] min-w-0 sticky top-6">
            <div ref={codeContainerRef} className="max-h-[calc(100vh-7rem)] overflow-y-auto">
              {code === null ? <div className="p-4 text-xs text-gray-500 dark:text-gray-400">Loading...</div> : <CodeBlock key={`${fileKey}-${activeBlock}`} language="rust" filename={currentFile.fname} lines highlight={JSON.stringify([...highlighted])}>
                  {code}
                </CodeBlock>}
            </div>
            <div className="mt-1 flex justify-end">
              <a href={`${currentFile.url}#L${currentFile.start}-L${currentFile.end}`} target="_blank" rel="noreferrer noopener" className="text-[0.6875rem] font-medium text-[#656d76] no-underline hover:text-[#1f2328] dark:text-[#8b949e] dark:hover:text-[#e6edf3]">
                See on GitHub
              </a>
            </div>
          </div>}
      </div>
    </div>;
};

Smart contracts store data in their account's state, which is public on the chain. The storage starts **empty** until a contract is deployed and the state is initialized.

It is important to know that the account's **code** and account's **storage** are **independent**. [Updating the code](../release/upgrade) does **not erase** the state.

<ExplainCode>
  <Block highlights="6-9,13-18" fname="auction">
    ### Defining the State

    The attributes of the `struct` marked as the contract define the data that will be stored.

    The contract can store all native types (e.g. `u8`, `string`, `HashMap`, `Vector`) as well as complex objects.

    For example, our Auction contract stores when the auction ends, and an object representing the highest bid.

    <Note>
      The structures that will be saved need a special macro that tells the SDK to store them [serialized in Borsh](./serialization).
    </Note>

    <Note>
      The SDK also provides [collections](./collections) to efficiently store collections of data.
    </Note>
  </Block>

  <Block highlights="" fname="auction" type="info">
    <Warning>
      Contracts pay for their storage by locking part of their balance.

      It currently costs \~**1Ⓝ** to store **100KB** of data.
    </Warning>
  </Block>

  <Block highlights="" fname="auction">
    ### Initializing the State

    After the contract is deployed, its state is empty and needs to be initialized with
    some initial values.

    There are two ways to initialize a state:

    1. By creating an initialization function
    2. By setting default values
  </Block>

  <Block highlights="12,22-34" fname="auction">
    ### I. Initialization Functions

    An option to initialize the state is to create an `initialization` function, which needs to be called before executing any other function.

    In our Auction example, the contract has an initialization function that sets when the auction ends. The contract derives the `PanicOnDefault`, which forces the user to call the init method denoted by the `#[init]` macro.

    <Note>
      It is a good practice to mark initialization functions as private. We will cover function types in the [functions section](./functions).
    </Note>
  </Block>

  <Block highlights="10-16" fname="hello">
    ### II. Default State

    Another option to initialize the state is to create a `Default` version of our contract's `struct`.

    For example, our "Hello World" contract has a default state with a `greeting` set to `"Hello"`.

    The first time the contract executes, the `Default` will be stored in the state, and the state will be considered initialized.

    <Note>
      The state can only be initialized once.
    </Note>
  </Block>

  <Block highlights="" fname="hello" type="info">
    <Note>
      **Lifecycle of the State**

      When a function is called, the contract's state is loaded from the storage and put into memory.

      The state is actually [stored serialized](./serialization), and the SDK takes a bit of time to deserialize it before the method can access it.

      When the method finishes executing successfully, all the changes to the state are serialized, and saved back to the storage.
    </Note>
  </Block>

  <Block highlights="" fname="hello" type="info">
    <Warning>
      **State and Code**

      In NEAR, the contract's code and contract's storage are **independent**.

      Updating the code of a contract does **not erase** the state, and can indeed lead to unexpected behavior or errors.

      Make sure to read the [updating a contract](../release/upgrade) if you run into issues.
    </Warning>
  </Block>

  <File fname="auction" url="https://github.com/near-examples/auctions-tutorial/blob/main/contract-rs/01-basic-auction/src/lib.rs" start="2" end="83" />

  <File fname="hello" url="https://github.com/near-examples/hello-near-examples/blob/main/contract-rs/src/lib.rs" start="2" end="32" />
</ExplainCode>
