Skip to content

Key Gateway

The Key Gateway adds new keys to the Key Registry.

If you want to add a new public key to a Farcaster account, use the Key Gateway.

Read

nonces

Returns the next available nonce for an address. Used for generating EIP-712 signatures in addFor.

ParametertypeDescription
owneraddressThe address to query the nonce for

Write

add

Add a new key for the caller's fid and set its state to Added. Revert if the key is already registered.

ParametertypeDescription
keyTypeuint32Must be set to 1. This is currently the only supported keyType.
keybytesThe public key to add
metadataTypeuint8Must be set to 1. This is currenlty the only supported metadataType.
metadatabytesEncoded SignedKeyRequestMetadata

addFor

Add a key on behalf of another fid by providing a signature. The owner must sign an EIP-712 Add message approving the key. Reverts if the key is already registered.

ParametertypeDescription
fidOwneraddressAddress of the fid owner
keyTypeuint32Must be set to 1. This is currently the only supported keyType.
keybytesThe public key to add
metadataTypeuint8Must be set to 1. This is currenlty the only supported metadataType.
metadatabytesEncoded SignedKeyRequestMetadata
deadlineuint256Signature expiration timestamp
sigbytesEIP-712 Add signature from fidOwner

Add signature

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

Add(address owner,uint32 keyType,bytes key,uint8 metadataType,bytes metadata,uint256 nonce,uint256 deadline)

ParametertypeDescription
owneraddressAddress that owns the fid. The typed message must be signed by this address.
keyTypeuint32Must be set to 1. This is currently the only supported keyType.
keybytesThe public key to add
metadataTypeuint8Must be set to 1. This is currenlty the only supported metadataType.
metadatabytesEncoded SignedKeyRequestMetadata
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 metadata = await getMetadata();
const nonce = await readNonce();
const deadline = getDeadline();

const eip712Signer = new ViemWalletEip712Signer(walletClient);
const signature = await eip712signer.signAdd({
  owner: account,
  keyType: 1,
  key: publicKey,
  metadataType: 1,
  metadata,
  nonce,
  deadline,
});
ts
import { KEY_GATEWAY_EIP_712_TYPES } from '@farcaster/hub-web';
import { bytesToHex } from 'viem';
import { walletClient, account } from './clients.ts';
import { getPublicKey } from './signer.ts';
import { getMetadata } from './metadata.ts';
import { readNonce, getDeadline } from './helpers.ts';

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

const signature = await walletClient.signTypedData({
  account,
  ...KEY_GATEWAY_EIP_712_TYPES,
  primaryType: 'Add',
  message: {
    owner: account,
    keyType: 1,
    key: bytesToHex(publicKey),
    metadataType: 1,
    metadata,
    nonce,
    deadline,
  },
});
ts
import { KEY_GATEWAY_ADDRESS, keyGatewayABI } 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_GATEWAY_ADDRESS,
    abi: keyGatewayABI,
    functionName: 'nonces',
    args: [account],
  });
};
ts
import { ViemLocalEip712Signer } from '@farcaster/hub-web';
import { privateKeyToAccount } from 'viem/accounts';
import { getDeadline } from './helpers.ts';
import { getPublicKey } from './signer.ts';

// App account
export const appAccount = privateKeyToAccount('0x...');

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

export const getMetadata = async () => {
  const eip712signer = new ViemLocalEip712Signer(appAccount);
  const metadata = await eip712signer.getSignedKeyRequestMetadata({
    requestFid: 9152n, // App fid
    key: publicKey,
    deadline,
  });
  if (metadata.isOk()) {
    return metadata.value;
  }
};
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
InvalidMetadatabcecb64aThe signed metadata provided with the key is invalid.
InvalidSignature8baa579fThe provided signature is invalid. It may be incorrectly formatted, or signed by the wrong address.
SignatureExpired0819bdcdThe provided signature has expired. Collect a new signature from the signer with a later deadline timestamp.

Source

KeyGateway.sol