mirror of
https://github.com/neynarxyz/create-farcaster-mini-app.git
synced 2025-12-05 08:52:31 -05:00
formatting
This commit is contained in:
@@ -1,25 +1,29 @@
|
||||
"use client";
|
||||
'use client';
|
||||
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useAccount, useSendTransaction, useWaitForTransactionReceipt } from "wagmi";
|
||||
import { base } from "wagmi/chains";
|
||||
import { Button } from "../Button";
|
||||
import { truncateAddress } from "../../../lib/truncateAddress";
|
||||
import { renderError } from "../../../lib/errorUtils";
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import {
|
||||
useAccount,
|
||||
useSendTransaction,
|
||||
useWaitForTransactionReceipt,
|
||||
} from 'wagmi';
|
||||
import { base } from 'wagmi/chains';
|
||||
import { Button } from '../Button';
|
||||
import { truncateAddress } from '../../../lib/truncateAddress';
|
||||
import { renderError } from '../../../lib/errorUtils';
|
||||
|
||||
/**
|
||||
* SendEth component handles sending ETH transactions to protocol guild addresses.
|
||||
*
|
||||
*
|
||||
* This component provides a simple interface for users to send small amounts
|
||||
* of ETH to protocol guild addresses. It automatically selects the appropriate
|
||||
* recipient address based on the current chain and displays transaction status.
|
||||
*
|
||||
*
|
||||
* Features:
|
||||
* - Chain-specific recipient addresses
|
||||
* - Transaction status tracking
|
||||
* - Error handling and display
|
||||
* - Transaction hash display
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <SendEth />
|
||||
@@ -36,32 +40,34 @@ export function SendEth() {
|
||||
isPending: isEthTransactionPending,
|
||||
} = useSendTransaction();
|
||||
|
||||
const { isLoading: isEthTransactionConfirming, isSuccess: isEthTransactionConfirmed } =
|
||||
useWaitForTransactionReceipt({
|
||||
hash: ethTransactionHash,
|
||||
});
|
||||
const {
|
||||
isLoading: isEthTransactionConfirming,
|
||||
isSuccess: isEthTransactionConfirmed,
|
||||
} = useWaitForTransactionReceipt({
|
||||
hash: ethTransactionHash,
|
||||
});
|
||||
|
||||
// --- Computed Values ---
|
||||
/**
|
||||
* Determines the recipient address based on the current chain.
|
||||
*
|
||||
*
|
||||
* Uses different protocol guild addresses for different chains:
|
||||
* - Base: 0x32e3C7fD24e175701A35c224f2238d18439C7dBC
|
||||
* - Other chains: 0xB3d8d7887693a9852734b4D25e9C0Bb35Ba8a830
|
||||
*
|
||||
*
|
||||
* @returns string - The recipient address for the current chain
|
||||
*/
|
||||
const protocolGuildRecipientAddress = useMemo(() => {
|
||||
// Protocol guild address
|
||||
return chainId === base.id
|
||||
? "0x32e3C7fD24e175701A35c224f2238d18439C7dBC"
|
||||
: "0xB3d8d7887693a9852734b4D25e9C0Bb35Ba8a830";
|
||||
? '0x32e3C7fD24e175701A35c224f2238d18439C7dBC'
|
||||
: '0xB3d8d7887693a9852734b4D25e9C0Bb35Ba8a830';
|
||||
}, [chainId]);
|
||||
|
||||
// --- Handlers ---
|
||||
/**
|
||||
* Handles sending the ETH transaction.
|
||||
*
|
||||
*
|
||||
* This function sends a small amount of ETH (1 wei) to the protocol guild
|
||||
* address for the current chain. The transaction is sent using the wagmi
|
||||
* sendTransaction hook.
|
||||
@@ -88,15 +94,15 @@ export function SendEth() {
|
||||
<div className="mt-2 text-xs">
|
||||
<div>Hash: {truncateAddress(ethTransactionHash)}</div>
|
||||
<div>
|
||||
Status:{" "}
|
||||
Status:{' '}
|
||||
{isEthTransactionConfirming
|
||||
? "Confirming..."
|
||||
? 'Confirming...'
|
||||
: isEthTransactionConfirmed
|
||||
? "Confirmed!"
|
||||
: "Pending"}
|
||||
? 'Confirmed!'
|
||||
: 'Pending'}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,32 @@
|
||||
"use client";
|
||||
'use client';
|
||||
|
||||
import { useCallback, useState } from "react";
|
||||
import { useConnection as useSolanaConnection, useWallet as useSolanaWallet } from '@solana/wallet-adapter-react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import {
|
||||
useConnection as useSolanaConnection,
|
||||
useWallet as useSolanaWallet,
|
||||
} from '@solana/wallet-adapter-react';
|
||||
import { PublicKey, SystemProgram, Transaction } from '@solana/web3.js';
|
||||
import { Button } from "../Button";
|
||||
import { truncateAddress } from "../../../lib/truncateAddress";
|
||||
import { renderError } from "../../../lib/errorUtils";
|
||||
import { Button } from '../Button';
|
||||
import { truncateAddress } from '../../../lib/truncateAddress';
|
||||
import { renderError } from '../../../lib/errorUtils';
|
||||
|
||||
/**
|
||||
* SendSolana component handles sending SOL transactions on Solana.
|
||||
*
|
||||
*
|
||||
* This component provides a simple interface for users to send SOL transactions
|
||||
* using their connected Solana wallet. It includes transaction status tracking
|
||||
* and error handling.
|
||||
*
|
||||
*
|
||||
* Features:
|
||||
* - SOL transaction sending
|
||||
* - Transaction status tracking
|
||||
* - Error handling and display
|
||||
* - Loading state management
|
||||
*
|
||||
*
|
||||
* Note: This component is a placeholder implementation. In a real application,
|
||||
* you would integrate with a Solana wallet adapter and transaction library
|
||||
* like @solana/web3.js to handle actual transactions.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <SendSolana />
|
||||
@@ -42,7 +45,8 @@ export function SendSolana() {
|
||||
|
||||
// This should be replaced but including it from the original demo
|
||||
// https://github.com/farcasterxyz/frames-v2-demo/blob/main/src/components/Demo.tsx#L718
|
||||
const ashoatsPhantomSolanaWallet = 'Ao3gLNZAsbrmnusWVqQCPMrcqNi6jdYgu8T6NCoXXQu1';
|
||||
const ashoatsPhantomSolanaWallet =
|
||||
'Ao3gLNZAsbrmnusWVqQCPMrcqNi6jdYgu8T6NCoXXQu1';
|
||||
|
||||
/**
|
||||
* Handles sending the Solana transaction
|
||||
@@ -67,12 +71,13 @@ export function SendSolana() {
|
||||
fromPubkey: new PublicKey(fromPubkeyStr),
|
||||
toPubkey: new PublicKey(toPubkeyStr),
|
||||
lamports: 0n,
|
||||
}),
|
||||
})
|
||||
);
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.feePayer = new PublicKey(fromPubkeyStr);
|
||||
|
||||
const simulation = await solanaConnection.simulateTransaction(transaction);
|
||||
const simulation =
|
||||
await solanaConnection.simulateTransaction(transaction);
|
||||
if (simulation.value.err) {
|
||||
// Gather logs and error details for debugging
|
||||
const logs = simulation.value.logs?.join('\n') ?? 'No logs';
|
||||
@@ -100,7 +105,8 @@ export function SendSolana() {
|
||||
>
|
||||
Send Transaction (sol)
|
||||
</Button>
|
||||
{solanaTransactionState.status === 'error' && renderError(solanaTransactionState.error)}
|
||||
{solanaTransactionState.status === 'error' &&
|
||||
renderError(solanaTransactionState.error)}
|
||||
{solanaTransactionState.status === 'success' && (
|
||||
<div className="mt-2 text-xs">
|
||||
<div>Hash: {truncateAddress(solanaTransactionState.signature)}</div>
|
||||
@@ -108,4 +114,4 @@ export function SendSolana() {
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
"use client";
|
||||
'use client';
|
||||
|
||||
import { useCallback } from "react";
|
||||
import { useAccount, useConnect, useSignMessage } from "wagmi";
|
||||
import { base } from "wagmi/chains";
|
||||
import { Button } from "../Button";
|
||||
import { config } from "../../providers/WagmiProvider";
|
||||
import { APP_NAME } from "../../../lib/constants";
|
||||
import { renderError } from "../../../lib/errorUtils";
|
||||
import { useCallback } from 'react';
|
||||
import { useAccount, useConnect, useSignMessage } from 'wagmi';
|
||||
import { base } from 'wagmi/chains';
|
||||
import { Button } from '../Button';
|
||||
import { config } from '../../providers/WagmiProvider';
|
||||
import { APP_NAME } from '../../../lib/constants';
|
||||
import { renderError } from '../../../lib/errorUtils';
|
||||
|
||||
/**
|
||||
* SignEvmMessage component handles signing messages on EVM-compatible chains.
|
||||
*
|
||||
*
|
||||
* This component provides a simple interface for users to sign messages using
|
||||
* their connected EVM wallet. It automatically handles wallet connection if
|
||||
* the user is not already connected, and displays the signature result.
|
||||
*
|
||||
*
|
||||
* Features:
|
||||
* - Automatic wallet connection if needed
|
||||
* - Message signing with app name
|
||||
* - Error handling and display
|
||||
* - Signature result display
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <SignEvmMessage />
|
||||
@@ -41,12 +41,12 @@ export function SignEvmMessage() {
|
||||
// --- Handlers ---
|
||||
/**
|
||||
* Handles the message signing process.
|
||||
*
|
||||
*
|
||||
* This function first ensures the user is connected to an EVM wallet,
|
||||
* then requests them to sign a message containing the app name.
|
||||
* If the user is not connected, it automatically connects using the
|
||||
* Farcaster Frame connector.
|
||||
*
|
||||
*
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
const signEvmMessage = useCallback(async () => {
|
||||
@@ -78,4 +78,4 @@ export function SignEvmMessage() {
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
"use client";
|
||||
'use client';
|
||||
|
||||
import { useCallback, useState } from "react";
|
||||
import { signIn, signOut, getCsrfToken } from "next-auth/react";
|
||||
import sdk, { SignIn as SignInCore } from "@farcaster/frame-sdk";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { Button } from "../Button";
|
||||
import { useCallback, useState } from 'react';
|
||||
import { signIn, signOut, getCsrfToken } from 'next-auth/react';
|
||||
import sdk, { SignIn as SignInCore } from '@farcaster/frame-sdk';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { Button } from '../Button';
|
||||
|
||||
/**
|
||||
* SignIn component handles Farcaster authentication using Sign-In with Farcaster (SIWF).
|
||||
*
|
||||
*
|
||||
* This component provides a complete authentication flow for Farcaster users:
|
||||
* - Generates nonces for secure authentication
|
||||
* - Handles the SIWF flow using the Farcaster SDK
|
||||
* - Manages NextAuth session state
|
||||
* - Provides sign-out functionality
|
||||
* - Displays authentication status and results
|
||||
*
|
||||
*
|
||||
* The component integrates with both the Farcaster Frame SDK and NextAuth
|
||||
* to provide seamless authentication within mini apps.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <SignIn />
|
||||
@@ -45,69 +45,69 @@ export function SignIn() {
|
||||
// --- Handlers ---
|
||||
/**
|
||||
* Generates a nonce for the sign-in process.
|
||||
*
|
||||
*
|
||||
* This function retrieves a CSRF token from NextAuth to use as a nonce
|
||||
* for the SIWF authentication flow. The nonce ensures the authentication
|
||||
* request is fresh and prevents replay attacks.
|
||||
*
|
||||
*
|
||||
* @returns Promise<string> - The generated nonce token
|
||||
* @throws Error if unable to generate nonce
|
||||
*/
|
||||
const getNonce = useCallback(async () => {
|
||||
const nonce = await getCsrfToken();
|
||||
if (!nonce) throw new Error("Unable to generate nonce");
|
||||
if (!nonce) throw new Error('Unable to generate nonce');
|
||||
return nonce;
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Handles the sign-in process using Farcaster SDK.
|
||||
*
|
||||
*
|
||||
* This function orchestrates the complete SIWF flow:
|
||||
* 1. Generates a nonce for security
|
||||
* 2. Calls the Farcaster SDK to initiate sign-in
|
||||
* 3. Submits the result to NextAuth for session management
|
||||
* 4. Handles various error conditions including user rejection
|
||||
*
|
||||
*
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
const handleSignIn = useCallback(async () => {
|
||||
try {
|
||||
setAuthState((prev) => ({ ...prev, signingIn: true }));
|
||||
setAuthState(prev => ({ ...prev, signingIn: true }));
|
||||
setSignInFailure(undefined);
|
||||
const nonce = await getNonce();
|
||||
const result = await sdk.actions.signIn({ nonce });
|
||||
setSignInResult(result);
|
||||
await signIn("credentials", {
|
||||
await signIn('credentials', {
|
||||
message: result.message,
|
||||
signature: result.signature,
|
||||
redirect: false,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof SignInCore.RejectedByUser) {
|
||||
setSignInFailure("Rejected by user");
|
||||
setSignInFailure('Rejected by user');
|
||||
return;
|
||||
}
|
||||
setSignInFailure("Unknown error");
|
||||
setSignInFailure('Unknown error');
|
||||
} finally {
|
||||
setAuthState((prev) => ({ ...prev, signingIn: false }));
|
||||
setAuthState(prev => ({ ...prev, signingIn: false }));
|
||||
}
|
||||
}, [getNonce]);
|
||||
|
||||
/**
|
||||
* Handles the sign-out process.
|
||||
*
|
||||
*
|
||||
* This function clears the NextAuth session and resets the local
|
||||
* sign-in result state to complete the sign-out flow.
|
||||
*
|
||||
*
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
const handleSignOut = useCallback(async () => {
|
||||
try {
|
||||
setAuthState((prev) => ({ ...prev, signingOut: true }));
|
||||
setAuthState(prev => ({ ...prev, signingOut: true }));
|
||||
await signOut({ redirect: false });
|
||||
setSignInResult(undefined);
|
||||
} finally {
|
||||
setAuthState((prev) => ({ ...prev, signingOut: false }));
|
||||
setAuthState(prev => ({ ...prev, signingOut: false }));
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -115,12 +115,12 @@ export function SignIn() {
|
||||
return (
|
||||
<>
|
||||
{/* Authentication Buttons */}
|
||||
{status !== "authenticated" && (
|
||||
{status !== 'authenticated' && (
|
||||
<Button onClick={handleSignIn} disabled={authState.signingIn}>
|
||||
Sign In with Farcaster
|
||||
</Button>
|
||||
)}
|
||||
{status === "authenticated" && (
|
||||
{status === 'authenticated' && (
|
||||
<Button onClick={handleSignOut} disabled={authState.signingOut}>
|
||||
Sign out
|
||||
</Button>
|
||||
@@ -155,4 +155,4 @@ export function SignIn() {
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
'use client';
|
||||
|
||||
import { useCallback, useState } from "react";
|
||||
import { Button } from "../Button";
|
||||
import { renderError } from "../../../lib/errorUtils";
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Button } from '../Button';
|
||||
import { renderError } from '../../../lib/errorUtils';
|
||||
|
||||
interface SignSolanaMessageProps {
|
||||
signMessage?: (message: Uint8Array) => Promise<Uint8Array>;
|
||||
@@ -10,20 +10,20 @@ interface SignSolanaMessageProps {
|
||||
|
||||
/**
|
||||
* SignSolanaMessage component handles signing messages on Solana.
|
||||
*
|
||||
*
|
||||
* This component provides a simple interface for users to sign messages using
|
||||
* their connected Solana wallet. It accepts a signMessage function as a prop
|
||||
* and handles the complete signing flow including error handling.
|
||||
*
|
||||
*
|
||||
* Features:
|
||||
* - Message signing with Solana wallet
|
||||
* - Error handling and display
|
||||
* - Signature result display (base64 encoded)
|
||||
* - Loading state management
|
||||
*
|
||||
*
|
||||
* @param props - Component props
|
||||
* @param props.signMessage - Function to sign messages with Solana wallet
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <SignSolanaMessage signMessage={solanaWallet.signMessage} />
|
||||
@@ -38,11 +38,11 @@ export function SignSolanaMessage({ signMessage }: SignSolanaMessageProps) {
|
||||
// --- Handlers ---
|
||||
/**
|
||||
* Handles the Solana message signing process.
|
||||
*
|
||||
*
|
||||
* This function encodes a message as UTF-8 bytes, signs it using the provided
|
||||
* signMessage function, and displays the base64-encoded signature result.
|
||||
* It includes comprehensive error handling and loading state management.
|
||||
*
|
||||
*
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
const handleSignMessage = useCallback(async () => {
|
||||
@@ -51,7 +51,7 @@ export function SignSolanaMessage({ signMessage }: SignSolanaMessageProps) {
|
||||
if (!signMessage) {
|
||||
throw new Error('no Solana signMessage');
|
||||
}
|
||||
const input = new TextEncoder().encode("Hello from Solana!");
|
||||
const input = new TextEncoder().encode('Hello from Solana!');
|
||||
const signatureBytes = await signMessage(input);
|
||||
const signature = btoa(String.fromCharCode(...signatureBytes));
|
||||
setSignature(signature);
|
||||
@@ -84,4 +84,4 @@ export function SignSolanaMessage({ signMessage }: SignSolanaMessageProps) {
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ export { SignIn } from './SignIn';
|
||||
export { SignEvmMessage } from './SignEvmMessage';
|
||||
export { SendEth } from './SendEth';
|
||||
export { SignSolanaMessage } from './SignSolanaMessage';
|
||||
export { SendSolana } from './SendSolana';
|
||||
export { SendSolana } from './SendSolana';
|
||||
|
||||
Reference in New Issue
Block a user