npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@spherity/timestamp

v1.2.0

Published

A library to create timestamps with merkle trees and the ERC-7506 trusted hint registry

Downloads

239

Readme

Timestamp

This library provides a simple interface for anchoring timestamps on the Ethereum blockchain using merkle trees.

Usage

To timestamp newly created data, you'll need to initialize the TimestampController by providing it with the leaves (your data) and the necessary encoding options. The library will then automatically generate a Merkle tree from your data.

Once you've created the timestamp, the next step is to anchor the Merkle tree's root hash to the Ethereum blockchain. This is done using the anchorRootHash method, which writes the root hash to the Ethereum blockchain's Trusted Hint Registry using the provided signer. During this process, an event is emitted that serves as proof of the data's existence at that specific point in time.

To verify the integrity of your data later on, you can use the verifyProof method. This method requires you to provide the leaf (your data) and the corresponding Merkle proof. The verification process confirms that the data hasn't been altered since it was timestamped and anchored to the blockchain.

For future verifications, you'll need to generate proofs. You can do this using either the getMerkleProof method for a single proof or the getAllMerkleProofs method if you need multiple proofs. It's highly recommended to store these proofs, along with their corresponding root hash. This practice ensures that you have easy access to the information needed for future verifications.

import { TimestampController } from "@spherity/timestamp";
import { JsonRpcProvider, Wallet, keccak256 } from "ethers";

async function main() {
  // Initialize provider
  const provider = new JsonRpcProvider("https://...");
  // Get signer
  const signer = await provider.getSigner();

  // Define contract options
  const contractOptions = {
    contractAddress: "0x1234567890123456789012345678901234567890", // Trusted Hint Registry contract address
    namespace: await signer.getAddress(), // Use signer's address as namespace
    list: keccak256(Buffer.from("timestampingList")), // Unique identifier for your list
  };

  // Define tree options with verifiable credentials
  const treeOptions = {
    leaves: [
      JSON.stringify({
        "@context": ["https://www.w3.org/2018/credentials/v1"],
        type: ["VerifiableCredential"],
        issuer: "did:example:123",
        issuanceDate: "2023-06-15T00:00:00Z",
        credentialSubject: {
          id: "did:example:456",
          name: "Alice",
        },
      }),
      JSON.stringify({
        "@context": ["https://www.w3.org/2018/credentials/v1"],
        type: ["VerifiableCredential"],
        issuer: "did:example:789",
        issuanceDate: "2023-06-16T00:00:00Z",
        credentialSubject: {
          id: "did:example:012",
          name: "Bob",
        },
      }),
    ],
    encoding: "string",
  };

  // Create TimestampController instance
  const controller = new TimestampController(
    signer,
    contractOptions,
    treeOptions
  );

  // Anchor root hash
  async function anchorRootHash() {
    const tx = await controller.anchorRootHash();
    console.log("Root hash anchored:", tx.hash);
  }

  // Get and verify merkle proof
  async function verifyProof() {
    const leaf = JSON.stringify({
      "@context": ["https://www.w3.org/2018/credentials/v1"],
      type: ["VerifiableCredential"],
      issuer: "did:example:123",
      issuanceDate: "2023-06-15T00:00:00Z",
      credentialSubject: {
        id: "did:example:456",
        name: "Alice",
      },
    });
    const merkle = controller.getMerkleProof(leaf);
    const verified = await controller.verifyProof(
      leaf,
      merkle.proof,
      new Date("2023-06-15T00:00:00Z"), // Date when the leaf was created
      7 * 24 * 3600 // Max time difference in seconds between leaf creation and timestamp of anchoring
    );
    console.log("Proof verified:", verified);
  }

  // Run example
  await anchorRootHash();
  await verifyProof();
}

In case you want to verify a merkle proof later on, you can construct the TimestampController with the same contract options and an already anchored root hash.

// Create TimestampController instance with an existing root hash
const existingRootHash = "0x1234567890...";
const controllerWithExistingRoot = new TimestampController(
  provider,
  contractOptions,
  { rootHash: existingRootHash }
);

// Verify a proof using the existing root hash
async function verifyExistingProof() {
  const leaf = [
    JSON.stringify({
      "@context": ["https://www.w3.org/2018/credentials/v1"],
      type: ["VerifiableCredential"],
      issuer: "did:example:789",
      issuanceDate: "2023-06-20T00:00:00Z",
      credentialSubject: {
        id: "did:example:101112",
        name: "Bob",
      },
    }),
  ];
  const proof = ["0xabcdef...", "0x123456..."];
  const verified = await controllerWithExistingRoot.verifyProof(
    leaf,
    proof,
    new Date("2023-06-20T00:00:00Z"), // Date when the leaf was created
    7 * 24 * 3600 // Max time difference in seconds between leaf creation and timestamp of anchoring
  );
  console.log("Existing proof verified:", verified);
}