<!-- tempo-docs-context -->
> Source: [/docs/accounts/account-configuration/account-upgrade](https://tempo.xyz/developers/docs/accounts/account-configuration/account-upgrade.md)
> Section: [Accounts](https://tempo.xyz/developers/docs/accounts.md). Create accounts, set up signing methods, policies, access keys, key rotation, and fees, and follow guides for users, automations, agents, and teams.
> [Documentation index](https://tempo.xyz/developers/llms.txt) · [Docs skill](https://tempo.xyz/developers/SKILL.md)

> Tempo MCP: Use `search`, `find_pages`, `read_page`, and `code` at `https://mcp.tempo.xyz` for Tempo and related documentation.
> If an indexed page is missing or reflects an older site, read this site’s [documentation index](https://tempo.xyz/developers/llms.txt) and Markdown pages directly.

# Account Upgrade

Adds backup signers to a single-key account without changing its address.

## Overview

An account upgrade turns a single-key account into a configurable account at the same address. A configurable account has several signers and a threshold. A single-key account works like a standard Ethereum account (an EOA). One key controls it, so losing that key loses the account. The upgrade is permanent.

:::warning
**Multiple signers arrive with the [T14 network upgrade](https://tempo.xyz/developers/docs/protocol/upgrades/t14).** Until T14 activates, an account with several signers and a threshold runs only on the [Tempo Accounts devnet](https://tempo.xyz/developers/docs/accounts/create#connect-to-the-devnet), not on mainnet or testnet, and may still change.
:::

Until T14, the upgrade transaction does nothing on mainnet or testnet. It succeeds and charges its fee, but the original key still approves alone. Tempo rejects transactions from the configurable account.

In the interactive web page, create a private-key account on the Tempo Accounts devnet, fund it from the faucet, and pay 1 AlphaUSD with it. Then upgrade it in place to a configurable account with the original key and a new backup key as signers and a threshold of 2. A payment signed by the original key alone is rejected, and a payment approved by both signers succeeds. The address and balance stay the same. Each step is a real devnet transaction.

<span id="make-a-single-key-account-recoverable" />

<span id="upgrade-an-existing-account" />

<span id="legacy-account-upgrade" />

<span id="what-an-upgrade-changes" />

<span id="what-changes" />

## Upgrade Effects

The upgrade gives the account a list of signers, each with a weight. It also sets a threshold, the total weight an approval needs. From then on, signers whose weights reach the threshold approve for the account. The original key approves only if you list it, at its weight. The address, balances, token approvals, nonce, contract storage, and access keys with their limits stay the same.

Contracts that verify signatures themselves, such as Permit2, may still accept the original key. The original key also still controls the address on other EVM chains.

<span id="choose-signers-and-threshold" />

## Choose Signers

List the original key and at least one backup signer. A backup can be a passkey on the user's device or a key your recovery provider holds.

| Setup | Threshold | Result |
| --- | --- | --- |
| Original key and one backup, each at weight 1 | 1 | Either key pays alone and replaces the other if it's lost. |
| Three signers at weight 1 | 2 | Every payment needs two approvals. |

In any setup, the signers left after losing any one must still reach the threshold ([Plan for Recovery](https://tempo.xyz/developers/docs/accounts/account-configuration#plan-for-recovery)).

[Revoke](https://tempo.xyz/developers/docs/accounts/access-keys/revocation) any access key you don't want before you upgrade.

## Send the Upgrade

The original key signs one transaction whose only call is `upgradeAccount(threshold, owners)` on Tempo's built-in multisig contract. Call it with `writeContractSync`, and stop unless the client is on the devnet. Set `feeToken` to the stablecoin that pays the fee. Without it, Viem sends a standard Ethereum transaction, and the upgrade reverts with `PrimitiveRootRequired`.

`client.ts` connects to the Tempo Accounts devnet ([set up the devnet key](https://tempo.xyz/developers/docs/accounts/create#connect-to-the-devnet)).

:::code-group
```ts [upgrade.ts]
import { concat, keccak256, parseAbi, toHex } from 'viem'
import { tempoDevnet } from 'viem/chains'
import { Account, Addresses } from 'viem/tempo'
import { client } from './client'

// Mainnet and testnet accept the transaction but don't upgrade the account.
if (client.chain.id !== tempoDevnet.id) throw new Error('Account upgrades run only on the Tempo Accounts devnet.') // [!code hl]

// The key that controls the account today
const original = Account.fromSecp256k1(process.env.PRIVATE_KEY as `0x${string}`)
// The backup signer's address. Its key stays on the user's device or with your recovery provider.
const backup = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8'

// The account's configuration after the upgrade
const account = Account.fromConfig({ // [!code hl]
  address: original.address, // [!code hl]
  owners: [original, backup], // [!code hl]
  threshold: 1, // [!code hl]
  salt: keccak256(concat([toHex('tempo:multisig:upgrade'), original.address])), // [!code hl]
  version: 1n, // [!code hl]
}) // [!code hl]
const { owners, threshold } = account.config

// A test stablecoin on the devnet
const token = '0x20c0000000000000000000000000000000000001'

await client.writeContractSync({ // [!code hl]
  account: original, // [!code hl]
  address: Addresses.nativeMultisig, // [!code hl]
  abi: parseAbi([ // [!code hl]
    'function upgradeAccount(uint8 threshold, (address owner, uint8 weight)[] owners) returns (bytes32)', // [!code hl]
  ]), // [!code hl]
  functionName: 'upgradeAccount', // [!code hl]
  args: [threshold, owners], // [!code hl]
  feeToken: token, // [!code hl]
}) // [!code hl]

// Save account.config. Your app rebuilds the account from it.
```

```ts [client.ts]
import { http } from 'viem'
import { tempoDevnet } from 'viem/chains'
import { createClient } from 'viem/tempo'

// The Tempo Accounts devnet. Its RPC needs a key, which Tempo gives you.
const rpcKey = process.env.TEMPO_DEVNET_RPC_KEY

export const client = createClient({
  chain: tempoDevnet,
  transport: http('https://rpc-t14-checkpoint.devnet.tempoxyz.dev', {
    fetchOptions: { headers: { Authorization: `Basic ${btoa(`previews:${rpcKey}`)}` } },
  }),
})
```
:::

The upgraded configuration uses `version: 1n` and a salt Tempo derives from the address. `account.config` lists the signers sorted by address, as Tempo requires.

After the upgrade, the record your app [saves](https://tempo.xyz/developers/docs/development/configurable-accounts#keep-the-current-configuration) is the account's only readable list of signers. Each time your app acts for the account, rebuild it from that record with `Account.fromConfig`. Attach the keys that approve, such as `original`. The other signers stay as addresses.

Viem signs with the attached keys until their weights reach the threshold. If they fall short, it throws `Local owners do not meet the threshold.` and sends nothing. Approvals can also come from [separate devices](https://tempo.xyz/developers/docs/accounts/policies/signing-thresholds#approvers-on-separate-devices).

[Adding](https://tempo.xyz/developers/docs/accounts/account-configuration/configuration-updates#add-a-signer) or [removing](https://tempo.xyz/developers/docs/accounts/account-configuration/configuration-updates#remove-a-signer) signers later raises the version. Save the `config` that `updateConfigSync` returns and rebuild the account from it. Otherwise the next transaction fails with `multisig configuration commitment mismatch`.

<span id="account-upgrade-limits" />

## Limits

* Only the original key can sign the upgrade. Access keys can't, but a [fee payer](https://tempo.xyz/developers/docs/accounts/fees/fee-sponsorship) can sponsor it.
* The upgrade must be the transaction's only call, with no `keyAuthorization` and no EIP-7702 authorization list.
* Accounts with contract code, an EIP-7702 delegation, or existing signers can't upgrade.
* Afterward, a direct signature from the original key fails with `RootKeyRetired` (`primitive root key retired`). Sign with the account rebuilt from the saved configuration instead.
* Upgraded accounts don't use the [recovery factory](https://tempo.xyz/developers/docs/accounts/account-configuration#recover-funds-sent-on-another-chain) for funds sent to their address on another chain.

## Related

[Account Configuration](https://tempo.xyz/developers/docs/accounts/account-configuration): Covers signers, weights, thresholds, and recovery planning.

[Configuration Updates](https://tempo.xyz/developers/docs/accounts/account-configuration/configuration-updates): Use for adding, removing, or replacing signers after the upgrade.

[Signing Thresholds](https://tempo.xyz/developers/docs/accounts/policies/signing-thresholds): Covers how signer weights approve a transaction.

[Single-Key Accounts](https://tempo.xyz/developers/docs/development/single-key-accounts#upgrade-to-a-configurable-account): Covers the protocol reference for the upgrade to a configurable account.
