mirror of
https://github.com/neynarxyz/create-farcaster-mini-app.git
synced 2025-12-07 09:52:31 -05:00
Add signer creation
This commit is contained in:
@@ -2,9 +2,15 @@ import { NextResponse } from 'next/server';
|
||||
import { getNeynarClient } from '~/lib/neynar';
|
||||
|
||||
export async function GET() {
|
||||
const client = getNeynarClient();
|
||||
|
||||
const response = await client.fetchNonce();
|
||||
|
||||
return NextResponse.json(response);
|
||||
try {
|
||||
const client = getNeynarClient();
|
||||
const response = await client.fetchNonce();
|
||||
return NextResponse.json(response);
|
||||
} catch (error) {
|
||||
console.error('Error fetching nonce:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch nonce' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,42 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getNeynarClient } from '~/lib/neynar';
|
||||
|
||||
export async function POST() {
|
||||
try {
|
||||
const neynarClient = getNeynarClient();
|
||||
const signer = await neynarClient.createSigner();
|
||||
return NextResponse.json(signer);
|
||||
} catch (error) {
|
||||
console.error('Error fetching signer:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch signer' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const message = searchParams.get('message');
|
||||
const signature = searchParams.get('signature');
|
||||
const signerUuid = searchParams.get('signerUuid');
|
||||
|
||||
if (!message) {
|
||||
if (!signerUuid) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Message parameter is required' },
|
||||
{ error: 'signerUuid is required' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!signature) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Signature parameter is required' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const client = getNeynarClient();
|
||||
|
||||
let signers;
|
||||
|
||||
try {
|
||||
const data = await client.fetchSigners({ message, signature });
|
||||
signers = data.signers;
|
||||
const neynarClient = getNeynarClient();
|
||||
const signer = await neynarClient.lookupSigner({
|
||||
signerUuid,
|
||||
});
|
||||
return NextResponse.json(signer);
|
||||
} catch (error) {
|
||||
console.error('Error fetching signers:', error?.response?.data);
|
||||
throw new Error('Failed to fetch signers');
|
||||
console.error('Error fetching signed key:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch signed key' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
console.log('signers =>', signers);
|
||||
|
||||
return NextResponse.json({
|
||||
signers,
|
||||
});
|
||||
}
|
||||
|
||||
101
src/app/api/auth/signer/signed_key/route.ts
Normal file
101
src/app/api/auth/signer/signed_key/route.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getNeynarClient } from '~/lib/neynar';
|
||||
import { mnemonicToAccount } from 'viem/accounts';
|
||||
|
||||
const postRequiredFields = ['signerUuid', 'publicKey'];
|
||||
|
||||
const SIGNED_KEY_REQUEST_VALIDATOR_EIP_712_DOMAIN = {
|
||||
name: 'Farcaster SignedKeyRequestValidator',
|
||||
version: '1',
|
||||
chainId: 10,
|
||||
verifyingContract:
|
||||
'0x00000000fc700472606ed4fa22623acf62c60553' as `0x${string}`,
|
||||
};
|
||||
|
||||
const SIGNED_KEY_REQUEST_TYPE = [
|
||||
{ name: 'requestFid', type: 'uint256' },
|
||||
{ name: 'key', type: 'bytes' },
|
||||
{ name: 'deadline', type: 'uint256' },
|
||||
];
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const body = await request.json();
|
||||
|
||||
// Validate required fields
|
||||
for (const field of postRequiredFields) {
|
||||
if (!body[field]) {
|
||||
return NextResponse.json(
|
||||
{ error: `${field} is required` },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const { signerUuid, publicKey, redirectUrl } = body;
|
||||
|
||||
if (redirectUrl && typeof redirectUrl !== 'string') {
|
||||
return NextResponse.json(
|
||||
{ error: 'redirectUrl must be a string' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the app's account from seed phrase
|
||||
const seedPhrase = process.env.SEED_PHRASE;
|
||||
const shouldSponsor = process.env.SPONSOR_SIGNER === 'true';
|
||||
|
||||
if (!seedPhrase) {
|
||||
return NextResponse.json(
|
||||
{ error: 'App configuration missing (SEED_PHRASE or FID)' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
const neynarClient = getNeynarClient();
|
||||
|
||||
const account = mnemonicToAccount(seedPhrase);
|
||||
|
||||
const {
|
||||
user: { fid },
|
||||
} = await neynarClient.lookupUserByCustodyAddress({
|
||||
custodyAddress: account.address,
|
||||
});
|
||||
|
||||
const appFid = fid;
|
||||
|
||||
// Generate deadline (24 hours from now)
|
||||
const deadline = Math.floor(Date.now() / 1000) + 86400;
|
||||
|
||||
// Generate EIP-712 signature
|
||||
const signature = await account.signTypedData({
|
||||
domain: SIGNED_KEY_REQUEST_VALIDATOR_EIP_712_DOMAIN,
|
||||
types: {
|
||||
SignedKeyRequest: SIGNED_KEY_REQUEST_TYPE,
|
||||
},
|
||||
primaryType: 'SignedKeyRequest',
|
||||
message: {
|
||||
requestFid: BigInt(appFid),
|
||||
key: publicKey,
|
||||
deadline: BigInt(deadline),
|
||||
},
|
||||
});
|
||||
|
||||
const signer = await neynarClient.registerSignedKey({
|
||||
appFid,
|
||||
deadline,
|
||||
signature,
|
||||
signerUuid,
|
||||
...(redirectUrl && { redirectUrl }),
|
||||
...(shouldSponsor && { sponsor: { sponsored_by_neynar: true } }),
|
||||
});
|
||||
|
||||
return NextResponse.json(signer);
|
||||
} catch (error) {
|
||||
console.error('Error registering signed key:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to register signed key' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
38
src/app/api/auth/signers/route.ts
Normal file
38
src/app/api/auth/signers/route.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getNeynarClient } from '~/lib/neynar';
|
||||
|
||||
const requiredParams = ['message', 'signature'];
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const params: Record<string, string | null> = {};
|
||||
for (const param of requiredParams) {
|
||||
params[param] = searchParams.get(param);
|
||||
if (!params[param]) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: `${param} parameter is required`,
|
||||
},
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const message = params.message as string;
|
||||
const signature = params.signature as string;
|
||||
|
||||
try {
|
||||
const client = getNeynarClient();
|
||||
const data = await client.fetchSigners({ message, signature });
|
||||
const signers = data.signers;
|
||||
return NextResponse.json({
|
||||
signers,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching signers:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch signers' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user