Skip to content

Commit

Permalink
Attestation
Browse files Browse the repository at this point in the history
  • Loading branch information
prathamthe1st committed Dec 7, 2024
1 parent f56089e commit e20b010
Show file tree
Hide file tree
Showing 6 changed files with 536 additions and 7 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"dependencies": {
"@apollo/client": "^3.12.2",
"@apollo/experimental-nextjs-app-support": "^0.11.7",
"@ethereum-attestation-service/eas-sdk": "^2.7.0",
"@graphprotocol/graph-cli": "^0.91.1",
"ethereum-blockies": "^0.1.1",
"framer-motion": "^11.13.1",
Expand Down
84 changes: 84 additions & 0 deletions packages/nextjs/app/testing/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"use client"
import React, { useState } from "react";
import { attestFitnessChallenge } from "../../helpers/Attest";

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 [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;
}

try {
const attestationId = await attestFitnessChallenge(userAddress, success, PRIVATE_KEY);
setResponse(`Attestation successful! Attestation ID: ${attestationId}`);
} catch (err: any) {
setError(err.message || "An error occurred during attestation.");
} finally {
setLoading(false);
}
};

return (
<div style={{ maxWidth: "600px", margin: "0 auto", textAlign: "center" }}>
<h1>Fitness Challenge Attestation</h1>

<div style={{ marginBottom: "20px" }}>
<label>
User Address:
<input
type="text"
value={userAddress}
onChange={e => setUserAddress(e.target.value)}
placeholder="Enter recipient address"
style={{ width: "100%", margin: "10px 0", padding: "10px", borderRadius: "5px" }}
/>
</label>
</div>

<div style={{ marginBottom: "20px" }}>
<label>
Challenge Completed:
<input
type="checkbox"
checked={success}
onChange={e => setSuccess(e.target.checked)}
style={{ marginLeft: "10px" }}
/>
</label>
</div>

<button
onClick={handleAttest}
style={{
padding: "10px 20px",
borderRadius: "5px",
background: "#0070f3",
color: "white",
border: "none",
cursor: "pointer",
}}
disabled={loading}
>
{loading ? "Attesting..." : "Attest"}
</button>

{response && <p style={{ color: "green", marginTop: "20px" }}>{response}</p>}
{error && <p style={{ color: "red", marginTop: "20px" }}>{error}</p>}
</div>
);
};

export default FitnessChallenge;
68 changes: 68 additions & 0 deletions packages/nextjs/helpers/Attest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
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";

// Generalized attestation function
export async function attestToSchema(
schemaKey: keyof typeof schemaIds,
attestationData: any,
// privateKey: string
) {
try {
const schemaId = schemaIds[schemaKey];
const encoder = encoders[schemaKey];

if (!schemaId || !encoder) {
throw new Error(`Schema ${schemaKey} not defined`);
}

// 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);

// 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
data: encodedData,
},
});

console.log(`Transaction hash for ${schemaKey}:`, tx.hash);

// Wait for confirmation
const receipt = await tx.wait();
console.log(`${schemaKey} attestation created successfully:`, receipt);

// Extract attestation ID from logs
const attestationId = receipt.logs[0].topics[1];
console.log(`${schemaKey} Attestation ID:`, attestationId);
return attestationId;
} catch (error) {
console.error(`Error attesting to ${schemaKey}:`, error);
throw error;
}
}

// Example usage for fitness challenge attestation
export async function attestFitnessChallenge(
userAddress: string,
success: boolean,
// privateKey: string
) {
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" },
]);
}
39 changes: 39 additions & 0 deletions packages/nextjs/helpers/EAS.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
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;
31 changes: 31 additions & 0 deletions packages/nextjs/helpers/Verify.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import eas from "./EAS";

// Function to verify attestation
export async function verifyAttestation(attestationId: string) {
try {
// Fetch attestation details
const attestation = await eas.getAttestation(attestationId);

if (!attestation) {
throw new Error("Attestation not found");
}

console.log("Attestation details:", attestation);

// Example: Check if the attestation is valid
if (attestation.revoked) {
throw new Error("Attestation has been revoked");
}

return {
isValid: true,
attestation,
};
} catch (error) {
console.error("Error verifying attestation:", error);
return {
isValid: false,
error: error.message,
};
}
}
Loading

0 comments on commit e20b010

Please sign in to comment.