From e8873a3829e8d800cc7a96ae1cca9bae506455bc Mon Sep 17 00:00:00 2001 From: Suja16 Date: Sun, 8 Dec 2024 02:38:19 +0530 Subject: [PATCH 1/2] back arrow added in navigaton --- packages/nextjs/app/leaderboard/page.tsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/nextjs/app/leaderboard/page.tsx b/packages/nextjs/app/leaderboard/page.tsx index 9a55458..106710d 100644 --- a/packages/nextjs/app/leaderboard/page.tsx +++ b/packages/nextjs/app/leaderboard/page.tsx @@ -1,6 +1,7 @@ "use client"; import React from "react"; +import { useRouter } from "next/navigation"; import { LEADERBOARD } from "./queries"; import { useQuery } from "@apollo/client"; import { motion } from "framer-motion"; @@ -21,6 +22,7 @@ interface LeaderboardEntry { } export default function Leaderboard() { + const router = useRouter(); const { data, loading, error } = useQuery(LEADERBOARD); if (loading) { @@ -53,9 +55,18 @@ export default function Leaderboard() { return (
- {/* Hero Section */} + {/* Hero Section with Back Button */}
-
+
+ {/* Back Button */} + +

Top Stakers

The highest stakers on our platform are showcased here

From 72bc235894f9fde4ad00a18bf1f980bc602e38e8 Mon Sep 17 00:00:00 2001 From: Dhruv1238 Date: Sat, 7 Dec 2024 21:22:35 +0000 Subject: [PATCH 2/2] feat: implement wallet connection and update attestation logic --- packages/nextjs/app/testing/page.tsx | 26 +++--- packages/nextjs/helpers/Attest.tsx | 71 ++++++++++------ packages/nextjs/helpers/EAS.tsx | 39 --------- packages/nextjs/utils/wagmi-utils.ts | 119 +++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 76 deletions(-) create mode 100644 packages/nextjs/utils/wagmi-utils.ts diff --git a/packages/nextjs/app/testing/page.tsx b/packages/nextjs/app/testing/page.tsx index 933654f..0cd690f 100644 --- a/packages/nextjs/app/testing/page.tsx +++ b/packages/nextjs/app/testing/page.tsx @@ -1,36 +1,38 @@ "use client" import React, { useState } from "react"; import { attestFitnessChallenge } from "../../helpers/Attest"; +import { requestWalletConnection, useSigner } from "~~/utils/wagmi-utils"; const FitnessChallenge = () => { const [userAddress, setUserAddress] = useState(""); const [success, setSuccess] = useState(false); const [response, setResponse] = useState(null); const [error, setError] = useState(null); + const { signer, isWalletConnected } = useSigner(); const [loading, setLoading] = useState(false); const handleAttest = async () => { - setLoading(true); - setResponse(null); - setError(null); - - const PRIVATE_KEY = process.env.NEXT_PUBLIC_PRIVATE_KEY; - if (!PRIVATE_KEY) { - setError("Private key is not configured. Please check your .env file."); - setLoading(false); - return; + // Explicitly request wallet connection if not connected + if (!isWalletConnected) { + const connected = await requestWalletConnection(); + if (!connected) { + setError("Failed to connect wallet"); + return; + } } + setLoading(true); try { - const attestationId = await attestFitnessChallenge(userAddress, success, PRIVATE_KEY); + const attestationId = await attestFitnessChallenge(userAddress, success, signer); setResponse(`Attestation successful! Attestation ID: ${attestationId}`); - } catch (err: any) { - setError(err.message || "An error occurred during attestation."); + } catch (err : any) { + setError(err.message || "Attestation failed"); } finally { setLoading(false); } }; + return (

Fitness Challenge Attestation

diff --git a/packages/nextjs/helpers/Attest.tsx b/packages/nextjs/helpers/Attest.tsx index 3fd72ac..507debc 100644 --- a/packages/nextjs/helpers/Attest.tsx +++ b/packages/nextjs/helpers/Attest.tsx @@ -1,16 +1,37 @@ -import { NO_EXPIRATION } from "@ethereum-attestation-service/eas-sdk"; -import eas, { schemaIds, encoders } from "./EAS"; -import { ethers } from "ethers"; -import { injected } from "wagmi/connectors"; -import { baseSepolia } from "viem/chains"; +import { NO_EXPIRATION, EAS, SchemaEncoder } from "@ethereum-attestation-service/eas-sdk"; + +// EAS Contract Address for Base Sepolia +const EASContractAddress = "0x4200000000000000000000000000000000000015"; + +// Schema IDs (replace with actual deployed schema IDs) +const schemaIds = { + fitnessChallenge: "0x51a8a63da0f823d83d6355aee1e1643f58247253874fa36a70059b841287960e", + stakingGoal: "0x51a8a63da0f823d83d6355aee1e1643f58247253874fa36a70059b841287960e", + rewardDistribution: "0x51a8a63da0f823d83d6355aee1e1643f58247253874fa36a70059b841287960e", +}; + +// Schema Encoders for each schema +export const encoders = { + fitnessChallenge: new SchemaEncoder("address user, uint256 timestamp, bool success"), + stakingGoal: new SchemaEncoder("address user, uint256 timestamp, bool success"), + rewardDistribution: new SchemaEncoder("address user, uint256 timestamp, bool success"), +}; // Generalized attestation function export async function attestToSchema( schemaKey: keyof typeof schemaIds, - attestationData: any, - // privateKey: string + attestationData: { name: string, value: any, type: string }[], + signer: any ) { try { + // Ensure signer is connected + if (!signer) { + throw new Error("No signer provided"); + } + + const eas = new EAS(EASContractAddress); + eas.connect(signer); + const schemaId = schemaIds[schemaKey]; const encoder = encoders[schemaKey]; @@ -21,35 +42,35 @@ export async function attestToSchema( // Encode attestation data const encodedData = encoder.encodeData(attestationData); - // Initialize signer (replace with your wallet setup) - const wallet = new ethers.Wallet(privateKey, ethers.getDefaultProvider("base-sepolia")); - - // Connect wallet to EAS - eas.connect(wallet); + // Ensure recipient is a valid address + const recipient = attestationData.find(item => item.name === 'user')?.value; + if (!recipient) { + throw new Error("Recipient address is required"); + } // Create attestation const tx = await eas.attest({ schema: schemaId, data: { - recipient: attestationData[0].value, // Assume recipient is the first field - expirationTime: NO_EXPIRATION, // Never expires - revocable: false, // Cannot be revoked + recipient: recipient, + expirationTime: NO_EXPIRATION, + revocable: true, // Changed to true for more flexibility data: encodedData, }, }); - console.log(`Transaction hash for ${schemaKey}:`, tx.hash); - - // Wait for confirmation + // Wait for transaction confirmation const receipt = await tx.wait(); - console.log(`${schemaKey} attestation created successfully:`, receipt); - // Extract attestation ID from logs + // Extract attestation ID const attestationId = receipt.logs[0].topics[1]; - console.log(`${schemaKey} Attestation ID:`, attestationId); + + console.log(`Attestation created successfully. Transaction receipt: ${tx.receipt}`); + console.log(`Attestation ID: ${attestationId}`); + return attestationId; } catch (error) { - console.error(`Error attesting to ${schemaKey}:`, error); + console.error("Attestation Error:", error); throw error; } } @@ -58,11 +79,11 @@ export async function attestToSchema( export async function attestFitnessChallenge( userAddress: string, success: boolean, - // privateKey: string + signer: any ) { return attestToSchema("fitnessChallenge", [ { name: "user", value: userAddress, type: "address" }, { name: "timestamp", value: Math.floor(Date.now() / 1000), type: "uint256" }, { name: "success", value: success, type: "bool" }, - ]); -} + ], signer); +} \ No newline at end of file diff --git a/packages/nextjs/helpers/EAS.tsx b/packages/nextjs/helpers/EAS.tsx index 28153f7..e69de29 100644 --- a/packages/nextjs/helpers/EAS.tsx +++ b/packages/nextjs/helpers/EAS.tsx @@ -1,39 +0,0 @@ -import { - EAS, - SchemaEncoder, -} from "@ethereum-attestation-service/eas-sdk"; -import { ethers } from "ethers"; - -// EAS Contract Address for Base Sepolia -export const EASContractAddress = "0x4200000000000000000000000000000000000021"; - -// Initialize EAS SDK -const eas = new EAS(EASContractAddress); - -// Default provider for Base Sepolia -const provider = ethers.getDefaultProvider("sepolia"); - -// Connect provider to EAS -eas.connect(provider); - -// Schema IDs (replace with actual deployed schema IDs) -export const schemaIds = { - fitnessChallenge: "0x51a8a63da0f823d83d6355aee1e1643f58247253874fa36a70059b841287960e", - stakingGoal: "0x51a8a63da0f823d83d6355aee1e1643f58247253874fa36a70059b841287960e", - rewardDistribution: "0x51a8a63da0f823d83d6355aee1e1643f58247253874fa36a70059b841287960e", -}; - -// Schema Encoders for each schema -export const encoders = { - fitnessChallenge: new SchemaEncoder( - "address user, uint256 timestamp, bool success" - ), - stakingGoal: new SchemaEncoder( - "address user, uint256 timestamp, bool success" - ), - rewardDistribution: new SchemaEncoder( - "address user, uint256 timestamp, bool success" - ), -}; - -export default eas; diff --git a/packages/nextjs/utils/wagmi-utils.ts b/packages/nextjs/utils/wagmi-utils.ts new file mode 100644 index 0000000..45d7947 --- /dev/null +++ b/packages/nextjs/utils/wagmi-utils.ts @@ -0,0 +1,119 @@ +import { useEffect, useState } from "react"; +import type { JsonRpcProvider, JsonRpcSigner } from "ethers"; +import { ethers } from "ethers"; +import { type HttpTransport, PublicClient, WalletClient } from "viem"; +import { usePublicClient, useWalletClient, useAccount } from "wagmi"; + +export function publicClientToProvider(publicClient: PublicClient) { + const { chain, transport } = publicClient; + + if (!chain) { + throw new Error("Chain not found"); + } + + const network = { + chainId: chain.id, + name: chain.name, + ensAddress: chain.contracts?.ensRegistry?.address, + }; + if (transport.type === "fallback") { + const providers = (transport.transports as ReturnType[]).map( + ({ value }) => new ethers.JsonRpcProvider(value?.url, network), + ); + if (providers.length === 1) return providers[0]; + return new ethers.FallbackProvider(providers); + } + return new ethers.JsonRpcProvider(transport.url, network); +} + +export function walletClientToSigner(walletClient: WalletClient) { + const { account, chain, transport } = walletClient; + + if (!chain) { + throw new Error("Chain not found"); + } + + if (!account) { + throw new Error("Account not found"); + } + + const network = { + chainId: chain.id, + name: chain.name, + ensAddress: chain.contracts?.ensRegistry?.address, + }; + const provider = new ethers.BrowserProvider(transport, network); + return new ethers.JsonRpcSigner(provider, account.address); +} + +export function useSigner() { + const { data: walletClient } = useWalletClient(); + const { isConnected } = useAccount(); + + const [signer, setSigner] = useState(undefined); + + useEffect(() => { + async function getSigner() { + if (!walletClient || !isConnected) { + console.warn("Wallet not connected"); + setSigner(undefined); + return; + } + + try { + const tmpSigner = walletClientToSigner(walletClient); + setSigner(tmpSigner); + + // Additional wallet connection verification + try { + const address = await tmpSigner.getAddress(); + console.log("Connected wallet address:", address); + } catch (addressError) { + console.error("Error getting wallet address:", addressError); + setSigner(undefined); + } + } catch (signerError) { + console.error("Error creating signer:", signerError); + setSigner(undefined); + } + } + + getSigner(); + }, [walletClient, isConnected]); + + return { + signer, + isWalletConnected: !!signer + }; +} + +export function useProvider() { + const publicClient = usePublicClient(); + + const [provider, setProvider] = useState(undefined); + useEffect(() => { + async function getProvider() { + if (!publicClient) return; + + const tmpProvider = publicClientToProvider(publicClient); + + setProvider(tmpProvider as unknown as JsonRpcProvider); + } + + getProvider(); + }, [publicClient]); + return provider; +} + +// Utility function to request wallet connection +export async function requestWalletConnection() { + try { + // This assumes you're using wagmi's connect method + // You might need to import and use the appropriate connect method + await window.ethereum.request({ method: 'eth_requestAccounts' }); + return true; + } catch (error) { + console.error("Wallet connection error:", error); + return false; + } +} \ No newline at end of file