Skip to content

Commit

Permalink
Merge Resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
prathamthe1st committed Dec 7, 2024
2 parents a56dccd + 72bc235 commit 17e7b3c
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 85 deletions.
21 changes: 12 additions & 9 deletions packages/nextjs/app/leaderboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,18 @@ export default function Leaderboard() {

return (
<div className="flex flex-col h-screen">
{/* Hero Section */}
<div className="bg-dark-surface py-8 relative">
<button
onClick={() => router.push("/")}
className="absolute left-4 top-1/3 -translate-y-1/2 p-2 text-neon-green hover:text-white transition-colors"
>
<ArrowLeftIcon className="h-6 w-6" />
</button>
<div className="max-w-2xl mx-auto text-center">
{/* Hero Section with Back Button */}
<div className="bg-dark-surface py-8">
<div className="max-w-2xl mx-auto text-center relative">
{/* Back Button */}
<button
onClick={() => router.back()}
className="absolute left-6 top-1/4 -translate-y-1/2
text-neon-green text-5xl hover:text-green-400 transition-colors"
>
</button>

<h1 className="text-4xl font-bold mb-4 text-neon-green glow-text">Top Stakers</h1>
<p className="text-gray-300">The highest stakers on our platform are showcased here</p>
</div>
Expand Down
26 changes: 14 additions & 12 deletions packages/nextjs/app/testing/page.tsx
Original file line number Diff line number Diff line change
@@ -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<string | null>(null);
const [error, setError] = useState<string | null>(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 (
<div style={{ maxWidth: "600px", margin: "0 auto", textAlign: "center" }}>
<h1>Fitness Challenge Attestation</h1>
Expand Down
71 changes: 46 additions & 25 deletions packages/nextjs/helpers/Attest.tsx
Original file line number Diff line number Diff line change
@@ -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];

Expand All @@ -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;
}
}
Expand All @@ -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);
}
39 changes: 0 additions & 39 deletions packages/nextjs/helpers/EAS.tsx
Original file line number Diff line number Diff line change
@@ -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;
119 changes: 119 additions & 0 deletions packages/nextjs/utils/wagmi-utils.ts
Original file line number Diff line number Diff line change
@@ -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<HttpTransport>[]).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<JsonRpcSigner | undefined>(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<JsonRpcProvider | undefined>(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;
}
}

0 comments on commit 17e7b3c

Please sign in to comment.