> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://viem-bo77n7e5n-wevm.vercel.app/api/mcp` to find what you need.

# Accounts Plugin

## Overview

[`Relay.accounts`](/tempo/relay/plugins/accounts#relayaccounts) coordinates configurable
account approvals, config persistence, submission leases, and operation lookups.
Unrelated requests pass to the next plugin or execution client.

## Recipes

Choose a local relay to run plugins in your application, or connect to a remote
relay. For remote mode, [configure the server](/tempo/guides/relay/run#add-plugins)
with the plugins shown in the local configuration.

### Install the Plugin

:::code-group
```ts twoslash [viem.config.ts (Local Relay)] filename="viem.config.ts"
import { http } from 'viem'
import { createClient, Relay, Store, withRelay } from 'viem/tempo'

export const client = createClient({
  transport: withRelay(http(), {
    plugins: [Relay.accounts({ store: Store.memory() })], // [!code focus]
  }),
})
```

```ts twoslash [viem.config.ts (Remote Relay)] filename="viem.remote.config.ts"
import { http } from 'viem'
import { createClient } from 'viem/tempo'

// See https://viem.sh/tempo/guides/relay/run for instructions on running a relay.
export const client = createClient({
  transport: http('https://relay.example.com/rpc'), // [!code focus]
})
```
:::

Memory storage is process-local. For independent owners or multiple relay
instances, use the same persistent [atomic store](/tempo/utilities/Store). See
[Send Configurable Account Transactions](/tempo/guides/configurable-accounts/send) for the client
flow.

### Resolve Configs the Relay Has Not Seen

The plugin stores the configs that pass through it. Pass `resolveConfig` to look up any other
config, such as from an indexer of `ConfigurableAccountConfigUpdated` events. The plugin
stores a resolved config only when it matches the account and its onchain commitment.

```ts twoslash [viem.config.ts] filename="viem.config.ts"
import { http } from 'viem'
import {
  AccountConfig,
  createClient,
  Relay,
  Store,
  withRelay,
} from 'viem/tempo'

export const client = createClient({
  transport: withRelay(http(), {
    plugins: [
      Relay.accounts({
        async resolveConfig({ address, chainId, commitment }) { // [!code focus]
          const response = await fetch( // [!code focus]
            `https://indexer.example.com/configs/${chainId}/${address}/${commitment}`, // [!code focus]
          ) // [!code focus]
          if (!response.ok) return null // [!code focus]
          return AccountConfig.fromRpc(await response.json()) // [!code focus]
        }, // [!code focus]
        store: Store.memory(),
      }),
    ],
  }),
})
```

## `Relay.accounts`

Creates middleware that coordinates configurable account approvals. The middleware infers
chain IDs from parameters, signed transactions, key authorizations, and stored
operations, and rejects conflicts with an explicit chain.

### Usage

```ts twoslash
import { Relay, Store } from 'viem/tempo'

const plugin = Relay.accounts({ store: Store.memory() })
```

### Parameters

#### options.resolveConfig

* **Type:** `(options: Relay.accounts.resolveConfig.Options) => MaybePromise<AccountConfig.Config | null | undefined>`

Resolves a config that `store` does not hold. `account_getConfig` calls it with the account, its
chain, and the commitment read from that chain. The plugin stores and returns the result only
when it matches the account and commitment. Otherwise the response is `null`.

```ts twoslash
import { type AccountConfig, Relay, Store } from 'viem/tempo'

declare function findConfig(
  options: Relay.accounts.resolveConfig.Options,
): Promise<AccountConfig.Config | null>
// ---cut---
const plugin = Relay.accounts({
  resolveConfig: (options) => findConfig(options), // [!code focus]
  store: Store.memory(),
})
```

#### options.store

* **Type:** `Store.Atomic`

The shared store for configs, approvals, and submission state. Atomic
`compareAndSet` prevents concurrent approvals from overwriting one another.

```ts twoslash
import { Relay, Store } from 'viem/tempo'

const store = Store.memory()
// ---cut---
const plugin = Relay.accounts({ store }) // [!code focus]
```

### Return Value

`Relay.accounts.ReturnType`

A relay plugin with the `accounts` capability. Local `withRelay` transports use
this capability to enable coordinated transaction preparation.

### Errors

| Error | Description |
| --- | --- |
| `RpcResponse.InvalidParamsError` | The store lacks atomic operations, request parameters are invalid, or chain IDs conflict. |
| `Config.InvalidStoreValueError` | A stored config is invalid. |
| `Operation.InvalidStoreValueError` | A stored operation is invalid. |
| `Operation.StoreConflictError` | Concurrent store updates could not be reconciled. |

## RPC Methods

### `account_getConfig`

Reads the account's current config commitment and returns the matching validated config from the
shared store, or from `resolveConfig`. It returns `null` when neither holds that config. Configs are
stored per chain. The response includes the owner addresses and weights, so public handlers expose
cached owner lists.

### `eth_sendRawTransaction`

A partially approved transaction returns its operation hash. Once quorum is reached, the handler
broadcasts the canonical transaction and continues to return the operation hash.

### `eth_sendRawTransactionSync`

Below quorum, this method returns a pending receipt whose `transactionHash` is the operation hash
and whose `operation` property contains the current operation. At quorum, it returns the submitted
transaction receipt with the successful operation attached.

The pending receipt uses `null` for block, index, gas, and bloom fields because no transaction has
been submitted to the node yet.

### `eth_getTransactionByHash`

Passing an operation hash returns the pending transaction or aliases the lookup to the submitted
transaction. Before quorum, the handler constructs the pending transaction from the stored unsigned
Tempo transaction and selected approvals. Its block fields are `null`, its `hash` is the operation
hash, and its `operation` property contains the pending operation.

### `eth_getTransactionReceipt`

Passing a pending operation hash returns `null`. After submission, the handler aliases the lookup
to the final transaction receipt and attaches `operation`.
