> ## 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.

# Updating Contracts

> Learn how to upgrade NEAR smart contracts safely, including programmatic updates, migration strategies, and best practices for contract versioning.

export const Github = ({url, start, end, fname, language, withSourceLink = true}) => {
  const [code, setCode] = useState(null);
  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 fetchCode(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 body = res.split('\n');
    const from = fromLine ? Number(fromLine) - 1 : 0;
    const to = toLine ? Number(toLine) : body.length;
    body = body.slice(from, to);
    const precedingSpace = body.reduce((prev, line) => {
      if (line.length === 0) return prev;
      const spaces = line.match(/^\s+/);
      if (spaces) return Math.min(prev, spaces[0].length);
      return 0;
    }, Infinity);
    return body.map(line => line.slice(precedingSpace === Infinity ? 0 : precedingSpace)).join('\n');
  }
  function buildSourceUrl(url, start, end) {
    const base = url.split('#')[0];
    if (start && end) return `${base}#L${start}-L${end}`;
    if (start) return `${base}#L${start}`;
    return base;
  }
  useEffect(() => {
    const rawUrl = toRaw(url);
    fetchCode(rawUrl, start, end).then(res => setCode(res));
  }, [url, start, end]);
  const sourceUrl = buildSourceUrl(url, start, end);
  const fileName = fname ?? sourceUrl.split('/').pop();
  return <div className="my-5">
      {code === null ? <div>Loading...</div> : <CodeBlock language={language} filename={fileName} lines>
          {code}
        </CodeBlock>}
      {withSourceLink && <div className="flex justify-end" style={{
    marginTop: "-1rem"
  }}>
          <a href={sourceUrl} 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 code on GitHub
          </a>
        </div>}
    </div>;
};

Learn how to update NEAR smart contracts, both through tools like NEAR CLI and programmatically. Understand the implications of state migration when changing contract logic.

NEAR accounts separate their logic (contract's code) from their state (storage),
allowing the code to be changed.

Contract's can be updated in two ways:

1. **Through tools** such as [NEAR CLI](../../tools/cli) or the
   [NEAR API](../../tools/near-api) (if you hold
   the account's
   [full access key](../../protocol/accounts-contracts/access-keys)).
2. **Programmatically**, by implementing a method that
   [takes the new code and deploys it](#programmatic-update).

***

## Updating Through Tools

Simply re-deploy another contract using your preferred tool, for example, using
[NEAR CLI](../../tools/cli):

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# (optional) If you don't have an account, create one
near create-account <account-id> --useFaucet

# Deploy the contract
near deploy <account-id> <wasm-file>
```

***

## Programmatic Update

A smart contract can also update itself by implementing a method that:

1. Takes the new wasm contract as input
2. Creates a Promise to deploy it on itself

<Github fname="update.rs" language="rust" url="https://github.com/near-examples/update-migrate-rust/blob/main/self-updates/base/src/update.rs" start="10" end="31" />

#### How to Invoke Such Method?

<Tabs>
  <Tab title="CLI">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    # Call the update_contract method
    near contract call-function as-transaction <contract-account> update_contract file-args </path/to/wasm.wasm> prepaid-gas '300.0 Tgas' attached-deposit '0 NEAR' sign-as <manager-account> network-config testnet sign-with-keychain send
    ```
  </Tab>
</Tabs>

<Tip>
  **DAO Factories**

  This is how DAO factories
  [update their contracts](https://github.com/near-daos/sputnik-dao-contract/blob/main/sputnikdao-factory2/src/factory_manager.rs#L60)
</Tip>

***

## Migrating the State

Since the account's logic (smart contract) is separated from the account's state
(storage), **the account's state persists** when re-deploying a contract.

Because of this, **adding methods** or **modifying existing ones** will yield
**no problems**.

However, deploying a contract that **modifies or removes structures** stored in
the state will raise an error: `Cannot deserialize the contract state`, in which
case you can choose to:

1. Use a different account
2. Rollback to the previous contract code
3. Add a method to migrate the contract's state

<hr className="subsection" />

### The Migration Method

If you have no option but to migrate the state, then you need to implement a
method that:

1. Reads the current state of the contract
2. Applies different functions to transform it into the new state
3. Returns the new state

<Tip>
  **DAO Update**

  This is how DAOs
  [update themselves](https://github.com/near-daos/sputnik-dao-contract/blob/main/sputnikdao2/src/upgrade.rs#L59)
</Tip>

<hr className="subsection" />

### Example: Guest Book Migration

Imagine you have a Guest Book where you store messages, and the users can pay
for such messages to be "premium". You keep track of the messages and payments
using the following state:

<Github fname="lib.rs" language="rust" url="https://github.com/near-examples/update-migrate-rust/blob/main/basic-updates/base/src/lib.rs" start="10" end="21" />

#### Update Contract

At some point you realize that you could keep track of the `payments` inside of
the `PostedMessage` itself, so you change the contract to:

<Github fname="lib.rs" language="rust" url="https://github.com/near-examples/update-migrate-rust/blob/main/basic-updates/update/src/lib.rs" start="12" end="23" />

#### Incompatible States

If you deploy the update into an initialized account the contract will fail to
deserialize the account's state, because:

1. There is an extra `payments` vector saved in the state (from the previous
   contract)
2. The stored `PostedMessages` are missing the `payment` field (as in the
   previous contract)

#### Migrating the State

To fix the problem, you need to implement a method that goes through the old
state, removes the `payments` vector and adds the information to the
`PostedMessages`:

<Github fname="migrate.rs" language="rust" url="https://github.com/near-examples/update-migrate-rust/blob/main/basic-updates/update/src/migrate.rs" start="3" end="51" />

Notice that `migrate` is actually an [initialization method](../anatomy/storage) that **ignores** the existing state (`#[init(ignore_state)]`), thus being able to execute and rewrite the state.

<Accordion title="Why we should remove old structures from the state?">
  To understand why we should remove old structures from the state let's take a look to how the data is stored.

  For example, if the old version of the contract stores two messages with payments according methods `get_messages` and `get_payments` will return the following results:

  <Accordion title="get_messags result">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    INFO --- Result -------------------------
    |    [
    |      {
    |        "premium": false,
    |        "sender": "test-ac-1719933221123-3.testnet",
    |        "text": "Hello"
    |      },
    |      {
    |        "premium": false,
    |        "sender": "test-ac-1719933221123-3.testnet",
    |        "text": "Hello"
    |      }
    |    ]
    |    ------------------------------------
    ```
  </Accordion>

  <Accordion title="get_payments result">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    INFO --- Result -------------------------
     |    [
     |      "10000000000000000000000",
     |      "10000000000000000000000"
     |    ]
     |    ------------------------------------
    ```
  </Accordion>

  But if we take a look at the storage as text using following command, we will see that each payment is stored under its own key started with `p\` prefix.

  ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
  near contract view-storage <CONTRACT_ID> all as-text network-config testnet now
  ```

  <Accordion title="Storage as text result">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    INFO Contract state (values):
     |      key:   STATE
     |      value: \x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00m\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00p
     |      --------------------------------
     |      key:   m\x00\x00\x00\x00\x00\x00\x00\x00
     |      value: \x00\x1f\x00\x00\x00test-ac-1719933221123-3.testnet\x05\x00\x00\x00Hello
     |      --------------------------------
     |      key:   m\x01\x00\x00\x00\x00\x00\x00\x00
     |      value: \x00\x1f\x00\x00\x00test-ac-1719933221123-3.testnet\x05\x00\x00\x00Hello
     |      --------------------------------
     |      key:   p\x00\x00\x00\x00\x00\x00\x00\x00
     |      value: \x00\x00@\xb2\xba\xc9\xe0\x19\x1e\x02\x00\x00\x00\x00\x00\x00
     |      --------------------------------
     |      key:   p\x01\x00\x00\x00\x00\x00\x00\x00
     |      value: \x00\x00@\xb2\xba\xc9\xe0\x19\x1e\x02\x00\x00\x00\x00\x00\x00
     |      --------------------------------
    ```
  </Accordion>

  That means that while migrating the state to a new version we need not only change the messages structure, but also remove all payments related keys from the state. Otherwise, the old keys will simply stay behind being orphan, still occupying space.

  To remove them in `migrate` method, we call `clear()` method on payments vector in mutable `old_state` struct. This method removes all elements from the collection.
</Accordion>

<Tip>
  You can follow a migration step by step in the
  [official migration example](https://github.com/near-examples/update-migrate-rust/tree/main/basic-updates/base)
</Tip>

***

## State versioning

State versioning lets old and new representations coexist. Instead of rewriting every stored value during one migration, store an enum whose variants represent each supported version:

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[derive(BorshDeserialize, BorshSerialize)]
pub enum VersionedPostedMessage {
    V1(PostedMessageV1),
    V2(PostedMessageV2),
}
```

When the contract reads an older variant, it can convert it to the latest representation before applying new logic. This makes future changes easier, but it also means the contract must continue understanding every version that can remain in storage.

See the [state-versioning example](https://github.com/near-examples/update-migrate-rust/tree/main/enum-updates) for a complete implementation.

***

## Locking a contract account

You can prevent external actors from upgrading a contract by removing every full-access key from its account. Once the keys are removed, nobody can sign transactions in the account's name to deploy new code or transfer its balance.

First, list the account's keys and identify every full-access key:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
near list-keys <contract-account>
```

Then remove each full-access key:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
near delete-key <contract-account> '<public-key>'
```

<Warning>
  Removing all full-access keys cannot be undone through an externally signed transaction. Confirm that you have the intended upgrade and recovery design before locking the account.
</Warning>

A locked contract can still upgrade itself if its current code exposes an authorized [programmatic update](#programmatic-update) method. If the contract must be permanently immutable, do not include such a method.
