✨Works out of the box guarantee. If you face any issue at all, hit us up on Telegram and we will write the integration for you.

Other SDKs
Diamante
Quickstart

Publish On-Chain with Reclaim on Diamante

Pre-requisite

At this stage, we assume that you are familiar with the steps at ReactJs.

Before diving into this walkthrough, ensure you're familiar with the basic concepts of zkApps on the Mina Protocol and have a compatible wallet installed. We'll guide you through setting up your environment, deploying the smart contract, and running the frontend application.

To follow this guide, ensure you have the following:

Setting Up Your Wallet

  1. Install Diamante Wallet: Download and install the wallet extension from the provided link (opens in a new tab).
  2. Switch to Diamante Testnet:
    • Open wallet settings.
    • Navigate to "Networks".
    • Select "Diamante Testnet".
  3. Fund Your Wallet: Obtain testnet tokens from the Diamante Faucet.

Accessing the Code

Clone the repository for the Starterpack:

Project Overview

This project demonstrates how to verify proofs using the Reclaim Protocol and register them on the Diamante blockchain. The process involves:

  • Generating proof requests using the Reclaim SDK.
  • Submitting verified proof data to the Diamante blockchain for immutable storage.

Workflow Summary

  1. Proof Verification:
    • Perform verification using the Reclaim infrastructure.
    • Handle computationally intensive tasks off-chain.
  2. On-Chain Proof Registration:
    • Record essential proof data (identifier and status) on Diamante’s Account Storage Layer.
  3. Verification Query:
    • Query proof status on-chain and cross-reference with off-chain records for full verification.

Steps to Run the Project

# Clone the repository
git clone https://gitlab.reclaimprotocol.org/starterpacks/reclaim-diamante-example.git
cd reclaim-diamante-example

# Install dependencies for backend and frontend
cd backend
npm install
cd ../frontend
npm install

Start the Backend Server

cd backend
node index.js

The backend will run on http://localhost:3001.

Start the Frontend

cd frontend
npm run dev

Access the app at http://localhost:5173.

Using the Application

  1. Connect Wallet:
    • Open the app.
    • Use the "Connect Wallet" button to link your Diamante Wallet.
  2. Generate Proof Request:
    • Click "Create Claim" to generate a proof request.
    • Scan the displayed QR code with the Reclaim app to start verification.
  3. Submit Proof:
    • Once the proof is verified, the app will display a "Verify Proof" button.
    • Click the button to submit the proof to the Diamante blockchain.
  4. Check Transaction:
    • After submission, a link to the Diamante Testnet Explorer will appear.
    • Use it to view transaction details.

Technical Details

Frontend

App.jsx

  • Integrates Reclaim SDK to handle proof requests and verification.
  • Connects to Diamante Wallet for submitting transactions.
  • Fill in your Reclaim credentials marked with //TODOs.
import { useState, useEffect } from "react";
import { ReclaimProofRequest } from "@reclaimprotocol/js-sdk";
import QRCode from "react-qr-code";
import { verifyProof } from "@reclaimprotocol/js-sdk";
import { submitTransaction } from "./utils/submitTransaction";
import { Hourglass } from "react-loader-spinner";
import ConnectWalletButton from "./components/ConnectWallet";
 
function App() {
  const [reclaimProofRequest, setReclaimProofRequest] = useState(null);
  const [requestUrl, setRequestUrl] = useState("");
  const [connectionStatus, setConnectionStatus] = useState({
    isConnected: false,
    userPublicKey: null,
  });
 
  const [statusUrl, setStatusUrl] = useState("");
  const [txLoading, setTxLoading] = useState(false);
  const [hash, setHash] = useState("");
 
  useEffect(() => {
    async function initializeReclaim() {
      const APP_ID = "0x6E0338a6D8594101Ea9e13840449242015d71B19"; //TODO: This is an example App Id Replace it with your App Id.
      const APP_SECRET =
        "0x1e0d6a6548b72286d747b4ac9f2ad6b07eba8ad6a99cb1191890ea3f77fae48f"; //TODO: This is an example App Secret Replace it with your App Secret.
      const PROVIDER_ID = "6d3f6753-7ee6-49ee-a545-62f1b1822ae5"; //TODO: This is GitHub Provider Id Replace it with the provider id you want to use.
 
      const proofRequest = await ReclaimProofRequest.init(
        APP_ID,
        APP_SECRET,
        PROVIDER_ID
      );
      setReclaimProofRequest(proofRequest);
    }
 
    initializeReclaim();
  }, []);
 
  async function handleCreateClaim() {
    if (!reclaimProofRequest) {
      console.error("Reclaim Proof Request not initialized");
      return;
    }
    const url = await reclaimProofRequest.getRequestUrl();
    setRequestUrl(url);
    const status = reclaimProofRequest.getStatusUrl();
    setStatusUrl(status);
    await reclaimProofRequest.startSession({
      onSuccess: async (proof) => {
        let result = await verifyProof(proof);
        if (result) {
          // Proof verification successful, submit transaction
          setTxLoading(true);
          const txHash = await submitTransaction(proof);
          setTxLoading(false);
          setHash(txHash);
        }
      },
      onFailure: (error) => {
        console.error("Verification failed", error);
        setTxLoading(false);
      },
    });
  }
 
  const handleConnectionChange = (status) => {
    setConnectionStatus(status);
  };
 
  return (
    <div className="flex flex-col gap-4 justify-center items-center mt-24">
      <h1>Verify Proofs on Diamante With Reclaim Protocol</h1>
      <ConnectWalletButton onConnectionChange={handleConnectionChange} />
      {/*Rest of Components */}
    </div>
  );
}
 
export default App;

src/utils/submitTransaction.js

  • Handles proof submission to the backend.
  • Manages wallet connection and transaction signing.
export async function submitTransaction(proof) {
  try {
    if (!window.diam) {
      console.error("DIAM Wallet is not installed or not detected.");
      alert("Please install DIAM Wallet to proceed.");
      return;
    }
    const result = await window.diam.connect();
    const userPublicKey = result.message.data[0].diamPublicKey;
 
    if (!userPublicKey) {
      console.error("Failed to retrieve public key from DIAM Wallet.");
      alert("Could not connect to DIAM Wallet.");
      return;
    }
 
    const response = await fetch("http://localhost:3001/create-transaction", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        userPublicKey,
        key: proof.identifier,
        value: "verified",
      }),
    });
 
    const { unsignedTransactionXDR } = await response.json();
    if (!unsignedTransactionXDR) {
      console.error("Failed to retrieve unsigned transaction XDR.");
      alert("Could not create the transaction.");
      return;
    }
    const signedTransactionResponse = await window.diam.sign(
      unsignedTransactionXDR,
      false,
      "Diamante Testnet 2024"
    );
    const signedTransactionXDR = signedTransactionResponse.message.data;
    console.log(
      "Signed Transaction XDR from DIAM Wallet:",
      signedTransactionXDR
    );
 
    const submitResponse = await fetch(
      "http://localhost:3001/submit-transaction",
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ signedTransactionXDR }),
      }
    );
 
    const res = await submitResponse.json();
 
    return res.hash;
  } catch (error) {
    console.error("Error managing data:", error.message);
  }
}

Backend

index.js

  • Exposes APIs for creating and submitting transactions to the Diamante blockchain.
  • Uses Diamante SDK for interacting with the blockchain.
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const DiamSdk = require("diamnet-sdk");
const crypto = require("crypto");
 
const app = express();
const port = 3001;
 
app.use(bodyParser.json());
app.use(cors());
 
app.post("/create-transaction", async (req, res) => {
  try {
    const { userPublicKey, key, value } = req.body;
 
    console.log("Received public key:", userPublicKey);
 
    if (!userPublicKey || !/^G[A-Z0-9]{55}$/.test(userPublicKey)) {
      throw new Error("Invalid or missing public key.");
    }
 
    const hashIdentifier = crypto
      .createHash("sha256")
      .update(key)
      .digest("hex")
      .slice(0, 64);
 
    const server = new DiamSdk.Aurora.Server(
      "https://diamtestnet.diamcircle.io/"
    );
    const account = await server.loadAccount(userPublicKey);
 
    const transaction = new DiamSdk.TransactionBuilder(account, {
      fee: await server.fetchBaseFee(),
      networkPassphrase: DiamSdk.Networks.TESTNET,
    })
      .addOperation(
        DiamSdk.Operation.manageData({
          name: hashIdentifier,
          value: value,
        })
      )
      .setTimeout(0)
      .build();
 
    const unsignedTransactionXDR = transaction.toXDR();
    res.json({ unsignedTransactionXDR });
  } catch (error) {
    console.error("Error in create-transaction:", error.message);
    res.status(500).json({ error: error.message });
  }
});
 
app.post("/submit-transaction", async (req, res) => {
  try {
    const { signedTransactionXDR } = req.body;
 
    if (!signedTransactionXDR || typeof signedTransactionXDR !== "string") {
      throw new Error("Invalid or missing signed transaction XDR.");
    }
 
    const server = new DiamSdk.Aurora.Server(
      "https://diamtestnet.diamcircle.io/"
    );
 
    const transaction = DiamSdk.TransactionBuilder.fromXDR(
      signedTransactionXDR,
      DiamSdk.Networks.TESTNET
    );
    const result = await server.submitTransaction(transaction);
    res.json(result);
  } catch (error) {
    console.error("Error in submit-transaction:", error);
    res.status(500).json({ error: error.message });
  }
});
 
app.listen(port, () => {
  console.log(`Backend listening at http://localhost:${port}`);
});

Notes

  • Replace placeholder APP_ID, APP_SECRET, and PROVIDER_ID in App.jsx with valid Reclaim credentials.
  • Ensure your wallet is connected to the Diamante Testnet before proceeding.