Skip to content

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

Read

totalKeys

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

ParametertypeDescription
fiduint256fid to look up
stateuint8 (1 for Added, 2 for Removed)State of the key (added or removed)

keysOf

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

ParametertypeDescription
fiduint256fid to look up
stateuint8 (1 for Added, 2 for Removed)State of the key (added or removed)
startIdxuint256 (optional)Start index for pagination
batchSizeuint256 (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.

keyDataOf

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

ParametertypeDescription
fiduint256fid to look up
keybytespublic key to check

Write

add

Will revert if called directly. Must be called via the Key Gateway

remove

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

ParametertypeDescription
keybytespublic key to remove

WARNING

Removing a key will delete all offchain messages associated with the key from Hubs.

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.

ParametertypeDescription
fidOwneraddressfid owner address
keybytespublic key to remove
deadlineuint256signature deadline
sigbytesEIP-712 signature from the fidOwner

WARNING

Removing a key will delete all offchain messages associated with the key from Hubs.

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)

ParametertypeDescription
owneraddressAddress that owns the fid. The typed message must be signed by this address.
keybytesThe public key to remove
nonceuint256Current nonce of the owner address
deadlineuint256Signature expiration timestamp
ts
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
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
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
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
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
export const account = privateKeyToAccount('0x...');

Errors

ErrorSelectorDescription
ExceedsMaximum29264042Adding the key exceeds the maximum number of keys allowed per fid (currently 1000)
InvalidSignature8baa579fThe provided signature is invalid. It may be incorrectly formatted, or signed by the wrong address.
InvalidStatebaf3f0f7The 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)
SignatureExpired0819bdcdThe provided signature has expired. Collect a new signature from the signer with a later deadline timestamp.

Source

KeyRegistry.sol