<!-- tempo-docs-context -->
> Source: [/docs/development/single-key-accounts](https://tempo.xyz/developers/docs/development/single-key-accounts.md)
> Section: [Tempo EVM](https://tempo.xyz/developers/docs/development.md). Build on Tempo EVM: wallets and keys, payments, transactions and fees, TIP-20 Tokens, contracts, exchange, network details, nodes, protocol specifications, and changelog.
> [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.

# Single-key accounts

A single-key account is an address derived from one public key, its root key, which has full control of the account.

Single-key accounts are live on mainnet and testnet. They work like an Ethereum account (an EOA), except the root key can also be a P-256 key or a passkey. A secp256k1 key has the same address on Tempo as on Ethereum and other EVM chains, but balances don't carry over between chains.

A single-key account's private key derives its address and can authorize access keys, extra keys that sign for the account.

<span id="compared-with-an-ethereum-eoa" />

## Single-key address derivation

The address is the last 20 bytes of `keccak256(x ‖ y)`, the hash of the root key's public key coordinates, the same rule Ethereum uses ([specification](https://tempo.xyz/developers/docs/protocol/transactions/spec-tempo-transaction#address-derivation)).

| Root key | Viem account |
| --- | --- |
| secp256k1 | `Account.fromSecp256k1(privateKey)` |
| P-256 | `Account.fromP256(privateKey)` |
| WebAuthn (passkey) | `Account.fromWebAuthnP256(credential)` |

Because the key fixes the address, you can't replace the root key: a new key is a new address. To change keys and keep the address, [upgrade to a configurable account](https://tempo.xyz/developers/docs/development/single-key-accounts#upgrade-to-a-configurable-account). A [configurable account](https://tempo.xyz/developers/docs/development/configurable-accounts) is one address controlled by weighted owner keys. Configurable accounts run only on the [Tempo Accounts devnet](https://tempo.xyz/developers/docs/accounts/create#connect-to-the-devnet), a test network, until [T14](https://tempo.xyz/developers/docs/protocol/upgrades/t14), the planned upgrade that brings them to testnet and mainnet.

## Signing with the root key

The root key signs transactions directly, in the [signature format](https://tempo.xyz/developers/docs/accounts/keys#tempo-transaction-signature-types) for its key type. The example sends 10 test stablecoins from the account to `RECIPIENT`. Set `ROOT_KEY` to the account's private key. Its `client.ts` is a Viem client for the Tempo Accounts devnet, whose RPC needs the `TEMPO_DEVNET_RPC_KEY` from [Connect to the devnet](https://tempo.xyz/developers/docs/accounts/create#connect-to-the-devnet).

On mainnet or Moderato, Tempo's testnet, which need no RPC key, use `createClient({ chain: tempo })` or `createClient({ chain: tempoModerato })` instead, with the chain from `viem/chains`, and pay network fees in that network's stablecoins, since Tempo has no native gas token. [Network details](https://tempo.xyz/developers/docs/quickstart/connection-details) lists both networks.

:::code-group
```ts [sign.ts]
import { parseUnits } from 'viem'
import { Account } from 'viem/tempo'
import { client } from './client'

// A test stablecoin on the devnet
const stablecoin = '0x20c0000000000000000000000000000000000001'
const account = Account.fromSecp256k1(process.env.ROOT_KEY as `0x${string}`) // [!code hl]

await client.token.transferSync({ // [!code hl]
  account, // [!code hl]
  amount: parseUnits('10', 6), // [!code hl]
  to: process.env.RECIPIENT as `0x${string}`, // [!code hl]
  token: stablecoin, // [!code hl]
}) // [!code hl]
```

```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}`)}` } },
  }),
})
```
:::

Any of the three key types can also sign EIP-7702 authorizations, which let the account run a contract's code as its own ([Tempo and EIP-7702](https://tempo.xyz/developers/docs/protocol/transactions/eip-7702)). An account with an EIP-7702 delegation can't [upgrade](https://tempo.xyz/developers/docs/development/single-key-accounts#upgrade-to-a-configurable-account).

## Access keys on a single-key account

The root key can authorize [access keys](https://tempo.xyz/developers/docs/development/account-keychain), extra keys that sign for the account within the spending limits, expiry, and call scopes you set. Scopes list the contracts, functions, and recipients a key can use. The root key keeps full authority and can revoke any of them. [Admin access keys](https://tempo.xyz/developers/docs/development/account-keychain#admin-access-keys), access keys with no limits, can manage keys too. To choose limits for a task, follow the [Access keys](https://tempo.xyz/developers/docs/accounts/access-keys) guide.

## Upgrade to a configurable account

An upgrade turns a single-key account into a [configurable account](https://tempo.xyz/developers/docs/development/configurable-accounts) at the same address, so you can add a backup key or rotate keys without moving funds. Owners approve instead of the root key, with weights that must reach a threshold. 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.
:::

The upgrade ([TIP-1113](https://tips.sh/1113)) takes effect only on the Tempo Accounts devnet until T14. On mainnet or testnet, the upgrade transaction does nothing. It succeeds and charges its fee, but the root key still approves alone. For a walkthrough with a demo that runs in your browser, follow [Account upgrade](https://tempo.xyz/developers/docs/accounts/account-configuration/account-upgrade).

| Property | Rule |
| --- | --- |
| Call | `upgradeAccount(threshold, owners)` on the native multisig precompile, a contract built into the devnet at `0xAACC000000000000000000000000000000000000` |
| Signed by | The root key, directly. Access keys can't upgrade. A [fee payer](https://tempo.xyz/developers/docs/accounts/fees/fee-sponsorship) can sponsor it. |
| Transaction | `upgradeAccount` is its only call, with no [`key_authorization`](https://tempo.xyz/developers/docs/development/account-keychain#authorize-an-access-key) or EIP-7702 authorization list |
| Eligible accounts | No contract code, no EIP-7702 delegation, and no configuration yet |
| Installed configuration | The owners and threshold, as version `1`, with salt `keccak256("tempo:multisig:upgrade" ‖ account)` |
| Kept | Address, balances, contract storage, token approvals, nonce, and access keys with their limits |
| Root key afterward | Can't sign directly on Tempo. It approves only if listed as an owner, with its weight. Other chains, and contracts that check signatures themselves, such as Permit2, may still accept it. |
| Event | `AccountUpgraded(account, commitment, salt, threshold, owners)` |

Viem 2.57.5 has no upgrade action, so call the precompile with `writeContractSync`, as in [Account upgrade](https://tempo.xyz/developers/docs/accounts/account-configuration/account-upgrade#send-the-upgrade). Every approval carries the configuration, so [save it](https://tempo.xyz/developers/docs/development/configurable-accounts#keep-the-current-configuration) with the account record.
