This guide walks you through generating a Signed Key Request using viem that need to be passed in while registering auth address

System & Installation Requirements

Prerequisites

  • Node.js >= 18.x (LTS recommended)
  • npm >= 9.x OR yarn >= 1.22.x

Download and install node (if not installed)

Initialize project (optional)

mkdir signed-key-request
cd signed-key-request
npm init -y

Install viem

npm install viem

OR with yarn:

yarn add viem

Code Breakdown and Steps

You can find full code at the end of this guide.

1

Import the required functions

The code starts by importing the necessary libraries:

import { encodeAbiParameters } from "viem";
import { mnemonicToAccount, generateMnemonic, english } from "viem/accounts";
2

Generate a random mnemonic and derive the auth address

Generates a mnemonic and converts it to an Ethereum address (auth_address)

const mnemonic = generateMnemonic(english);
const auth_address_acc = mnemonicToAccount(mnemonic);
const auth_address = auth_address_acc.address;
3

Define EIP-712 domain

Describes the EIP-712 domain (context of signature).

const SIGNED_KEY_REQUEST_VALIDATOR_EIP_712_DOMAIN = {
  name: "Farcaster SignedKeyRequestValidator",
  version: "1",
  chainId: 10,
  verifyingContract: "0x00000000fc700472606ed4fa22623acf62c60553",
};
4

Define the EIP-712 message structure

Defines the structure of the message to be signed.

const SIGNED_KEY_REQUEST_TYPE = [
  { name: "requestFid", type: "uint256" },
  { name: "key", type: "bytes" },
  { name: "deadline", type: "uint256" },
];
5

Encode the auth_address

Encodes auth_address as 32 bytes.

const key = encodeAbiParameters(
  [{ name: "auth_address", type: "address" }],
  [auth_address]
);
6

App details

Replace "MNEMONIC_HERE" with your app mnemonic phrase and fid with your app’s fid.

const fid = 0;
const account = mnemonicToAccount("MNEMONIC_HERE");
7

Define a deadline

Sets a 24-hour expiration time.

const deadline = Math.floor(Date.now() / 1000) + 86400;
8

Sign the EIP-712 message

Signs the message per EIP-712 standard.

const signature = await account.signTypedData({
  domain: SIGNED_KEY_REQUEST_VALIDATOR_EIP_712_DOMAIN,
  types: {
    SignedKeyRequest: SIGNED_KEY_REQUEST_TYPE,
  },
  primaryType: "SignedKeyRequest",
  message: {
    requestFid: BigInt(fid),
    key,
    deadline: BigInt(deadline),
  },
});
9

Create a sponsor signature

If you want to sponsor the auth address, you can sign the EIP-712 signature again with a basic Ethereum signature. This route needs to be sponsored if not provided then neynar will sponsor it for you and you will be charged in compute units.

const sponsorSignature = await account.signMessage({
  message: { raw: signature },
});
10

Print output

Prints useful values for further use.

console.log("auth_address", auth_address);
console.log("app_fid", fid);
console.log("signature", signature);
console.log("deadline", deadline);
console.log("sponsor.signature", sponsorSignature);
console.log("sponsor.fid", fid);
11

Run the code

Save the code in a file, e.g., generateSignedKeyRequest.js, and run it using Node.js:

node generateSignedKeyRequest.js
12

cURL

Use the generated values to make a cURL request to register the auth address. Replace <api-key> with your actual API key and <string> with your redirect URL(if needed).

curl --request POST \
   --url https://api.neynar.com/v2/farcaster/auth_address/developer_managed/signed_key/ \
   --header 'Content-Type: application/json' \
   --header 'x-api-key: <api-key>' \
   --data '{
   "address": "0x5a927ac639636e534b678e81768ca19e2c6280b7",
   "app_fid": 3,
   "deadline": 123,
   "signature": "0x16161933625ac90b7201625bfea0d816de0449ea1802d97a38c53eef3c9c0c424fefbc5c6fb5eabe3d4f161a36d18cda585cff7e77c677c5d34a9c87e68ede011c",
   "redirect_url": "<string>",
   "sponsor": {
     "fid": 3,
     "signature": "<string>",
     "sponsored_by_neynar": true
   }
 }'

Full Final Code


  import { encodeAbiParameters } from "viem";
  import { mnemonicToAccount, generateMnemonic, english } from "viem/accounts";

  (async () => {
    const mnemonic = generateMnemonic(english);
    const auth_address_acc = mnemonicToAccount(mnemonic);
    const auth_address = auth_address_acc.address;

    const SIGNED_KEY_REQUEST_VALIDATOR_EIP_712_DOMAIN = {
      name: "Farcaster SignedKeyRequestValidator",
      version: "1",
      chainId: 10,
      verifyingContract: "0x00000000fc700472606ed4fa22623acf62c60553",
    };

    const SIGNED_KEY_REQUEST_TYPE = [
      { name: "requestFid", type: "uint256" },
      { name: "key", type: "bytes" },
      { name: "deadline", type: "uint256" },
    ];

    const key = encodeAbiParameters(
      [{ name: "auth_address", type: "address" }],
      [auth_address]
    );

    const fid = 0;
    const account = mnemonicToAccount("MNEMONIC_HERE");

    const deadline = Math.floor(Date.now() / 1000) + 86400;

    const signature = await account.signTypedData({
      domain: SIGNED_KEY_REQUEST_VALIDATOR_EIP_712_DOMAIN,
      types: {
        SignedKeyRequest: SIGNED_KEY_REQUEST_TYPE,
      },
      primaryType: "SignedKeyRequest",
      message: {
        requestFid: BigInt(fid),
        key,
        deadline: BigInt(deadline),
      },
    });

    const sponsorSignature = await account.signMessage({
      message: { raw: signature },
    });

    console.log("auth_address", auth_address);
    console.log("app_fid", fid);
    console.log("signature", signature);
    console.log("deadline", deadline);
    console.log("sponsor.signature", sponsorSignature);
    console.log("sponsor.fid", fid);
  })();


Enjoy building! 🚀

For additional help, feel free to contact us.