> ## Documentation Index
> Fetch the complete documentation index at: https://docs.neynar.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Key Registry

The Key Registry stores the public keys associated with each Farcaster account.

If you want to read information about a Farcaster account's keys or remove an existing key, use the Key Registry.

If you want to add a new key, use the [Key Gateway](/farcaster/reference/contracts/reference/key-gateway) instead.

## Read

### totalKeys

Get the number of active keys (`uint256`) for an fid.

| Parameter | type                                 | Description                         |
| --------- | ------------------------------------ | ----------------------------------- |
| fid       | `uint256`                            | fid to look up                      |
| state     | `uint8` (1 for Added, 2 for Removed) | State of the key (added or removed) |

### keysOf

List all public keys (`bytes[]`) for an fid.

| Parameter | type                                 | Description                         |
| --------- | ------------------------------------ | ----------------------------------- |
| fid       | `uint256`                            | fid to look up                      |
| state     | `uint8` (1 for Added, 2 for Removed) | State of the key (added or removed) |
| startIdx  | `uint256` (optional)                 | Start index for pagination          |
| batchSize | `uint256` (optional)                 | Batch size for pagination           |

<Warning>
  Don't call this onchain! This function is very gas intensive. It's meant to be called by offchain tools, not by other contracts.
</Warning>

### keyDataOf

Returns the state (`uint8`) and keyType (`uint32`) of particular key for an fid.

| Parameter | type      | Description         |
| --------- | --------- | ------------------- |
| fid       | `uint256` | fid to look up      |
| key       | `bytes`   | public key to check |

## Write

### add

Will revert if called directly. Must be called via the [Key Gateway](/farcaster/reference/contracts/reference/key-gateway)

### remove

Removes a public key from the caller's fid and marks it as `Removed`.

| Parameter | type    | Description          |
| --------- | ------- | -------------------- |
| key       | `bytes` | public key to remove |

<Warning>
  Removing a key will delete all offchain messages associated with the key from Hubs.
</Warning>

### removeFor

Remove a key on behalf of another fid by providing a signature. The fid owner must sign an EIP-712 `Remove` message approving the removal. Reverts if the key does not exist or is already removed.

| Parameter | type      | Description                           |
| --------- | --------- | ------------------------------------- |
| fidOwner  | `address` | fid owner address                     |
| key       | `bytes`   | public key to remove                  |
| deadline  | `uint256` | signature deadline                    |
| sig       | `bytes`   | EIP-712 signature from the `fidOwner` |

<Warning>
  Removing a key will delete all offchain messages associated with the key from Hubs.
</Warning>

#### Remove signature

To remove a key on behalf of another account, you must provide an EIP-712 typed signature from the account in the following format:

`Remove(address owner,bytes key,uint256 nonce,uint256 deadline)`

| Parameter | type      | Description                                                                  |
| --------- | --------- | ---------------------------------------------------------------------------- |
| owner     | `address` | Address that owns the fid. The typed message must be signed by this address. |
| key       | `bytes`   | The public key to remove                                                     |
| nonce     | `uint256` | Current nonce of the `owner` address                                         |
| deadline  | `uint256` | Signature expiration timestamp                                               |

```ts [@farcaster/hub-web] theme={"system"}
import { ViemWalletEip712Signer } from '@farcaster/hub-web';
import { walletClient, account } from './clients.ts';
import { getPublicKey } from './signer.ts';
import { readNonce, getDeadline } from './helpers.ts';

const publicKey = await getPublicKey();
const nonce = await readNonce();
const deadline = getDeadline();

const eip712Signer = new ViemWalletEip712Signer(walletClient);
const signature = await eip712Signer.signRemove({
  owner: account,
  key: publicKey,
  nonce,
  deadline,
});
```

```ts [Viem] theme={"system"}
import { KEY_REGISTRY_EIP_712_TYPES } from '@farcaster/hub-web';
import { bytesToHex } from 'viem';
import { walletClient, account } from './clients.ts';
import { getPublicKey } from './signer.ts';
import { readNonce, getDeadline } from './helpers.ts';

const publicKey = await getPublicKey();
const nonce = await readNonce();
const deadline = getDeadline();

const signature = await walletClient.signTypedData({
  account,
  ...KEY_REGISTRY_EIP_712_TYPES,
  primaryType: 'Remove',
  message: {
    owner: account,
    key: bytesToHex(publicKey),
    nonce,
    deadline,
  },
});
```

```ts [helpers.ts] theme={"system"}
import { KEY_REGISTRY_ADDRESS, keyRegistryABI } from '@farcaster/hub-web';
import { publicClient, account } from './clients.ts';

export const getDeadline = () => {
  const now = Math.floor(Date.now() / 1000);
  const oneHour = 60 * 60;
  return now + oneHour;
};

export const readNonce = async () => {
  return await publicClient.readContract({
    address: KEY_REGISTRY_ADDRESS,
    abi: keyRegistryABI,
    functionName: 'nonces',
    args: [account],
  });
};
```

```ts [signer.ts] theme={"system"}
import * as ed from '@noble/ed25519';
import { NobleEd25519Signer } from '@farcaster/hub-web';

const privateKeyBytes = ed.utils.randomPrivateKey();
export const accountKey = new NobleEd25519Signer(privateKeyBytes);

export const getPublicKey = async () => {
  const accountKeyResult = await accountKey.getSignerKey();
  if (accountKeyResult.isOk()) {
    return accountKeyResult.value;
  }
};
```

```ts [clients.ts] theme={"system"}
import { createWalletClient, createPublicClient, custom, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { optimism } from 'viem/chains';

export const publicClient = createPublicClient({
  chain: optimism,
  transport: http(),
});

export const walletClient = createWalletClient({
  chain: optimism,
  transport: custom(window.ethereum),
});

// JSON-RPC Account
export const [account] = await walletClient.getAddresses();

// Local Account (use this OR the JSON-RPC account above, not both)
// export const account = privateKeyToAccount('0x...');
```

## Errors

| Error            | Selector   | Description                                                                                                                                            |
| ---------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| ExceedsMaximum   | `29264042` | Adding the key exceeds the maximum number of keys allowed per fid (currently 1000)                                                                     |
| InvalidSignature | `8baa579f` | The provided signature is invalid. It may be incorrectly formatted, or signed by the wrong address.                                                    |
| InvalidState     | `baf3f0f7` | The action violates state transition rules. (Adding a key that already exists, removing a key that does not exist, adding a key that has been removed) |
| SignatureExpired | `0819bdcd` | The provided signature has expired. Collect a new signature from the signer with a later deadline timestamp.                                           |

## Source

[`KeyRegistry.sol`](https://github.com/farcasterxyz/contracts/blob/1aceebe916de446f69b98ba1745a42f071785730/src/KeyRegistry.sol)
