Important Note

The Neynar Client Instantiation and API calls (fetchNonce and fetchSigners) should ideally be performed on the backend to protect your API key and maintain security.

Prerequisites

1

Ethereum-Enabled Browser

Browser Ensure you are using a browser with a wallet like MetaMask installed.

2

API Key

Obtain an API key from dev portal

3

Dependencies Installed

Install the required packages:

yarn add siwe viem @neynar/nodejs-sdk

Code Breakdown and Steps

1

Import Required Libraries

The code starts by importing the necessary libraries:

import { SiweMessage } from "siwe";
import { createWalletClient, custom, publicActions } from "viem";
import { optimism } from "viem/chains";
import { NeynarAPIClient, Configuration } from "@neynar/nodejs-sdk";
2

Configure Neynar API Client

Set up the Neynar API client with your API key and base path. Note that this should ideally be done on the backend for security reasons:

const config = new Configuration({
 apiKey: "YOUR_API_KEY_HERE",
});

const client = new NeynarAPIClient(config);
3

Create the Wallet Client

The createWalletClient function initializes a wallet client using the viem library. It uses window.ethereum to connect to the browser’s wallet:

const wallet = createWalletClient({
 chain: optimism,
 transport: custom(window.ethereum),
}).extend(publicActions);
4

Create the SIWE Message

The createSiweMessage function generates a SIWE message with details such as domain, address, and nonce:

async function createSiweMessage(address, statement) {
  const { nonce } = await client.fetchNonce();

  const message = new SiweMessage({
 scheme: "http",
 domain: "localhost:8080",
 address,
 statement,
 uri: "http://localhost:8080",
 version: "1",
 chainId: "1",
 nonce: nonce,
 });

  return message.prepareMessage();
}
5

Sign and Verify the Message

The fetchSigners function retrieves the user’s Ethereum address, generates a SIWE message, signs it, and verifies the signature using the Neynar API.

Note:

  1. Neynar API should ideally be accessed from the backend
  2. The address should be the custody_address of the farcaster account (Check custody_address here)
async function fetchSigners() {
  const address = (await wallet.getAddresses())[0];

  let message = await createSiweMessage(
 address,
    "Sign in with Ethereum to the app."
 );

  const signature = await wallet.signMessage({ account: address, message });

  const { signers } = await client.fetchSigners({ message, signature });

  return signers;
}
6

Execute the Function

Call the fetchSigners function and handle the response or errors:

fetchSigners()
 .then((signers) => {
 console.log("\n\nsigners:", signers, "\n\n");
 })
 .catch((error) => {
 console.error("error:", error);
 });

Expected Output

[
  {
    "object": "signer",
    "signer_uuid": "19d0c5fd-9b33-4a48-a0e2-bc7b0555baec",
    "public_key": "0xe4abc135d40f8a6ee216d1a6f2f4e82476dff75f71ea53c5bdebca43f5c415b7",
    "status": "approved",
    "fid": 0
  },
  {
    "object": "signer",
    "signer_uuid": "08c71152-c552-42e7-b094-f510ff44e9cb",
    "public_key": "0xe4cd577123def73295dd9991c589b59b48cdc976b5e83a9ad8d2a13fcfcc0e72",
    "status": "approved",
    "fid": 0
  }
]

For additional help, feel free to contact us.