Skip to content
forked from PinataCloud/ipcm

InterPlanetary CID Mapping Smart Contracts

License

Notifications You must be signed in to change notification settings

evanjrowley/ipcm

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IPCM

InterPlanetary CID Mapping

cover

IPCM is a smart contract that points to an IPFS CID which can be updated onchain, providing a simple solution to dynamic offchain data using IPFS

IPFS has been the go-to decentralized network for sharing content and websites. However it's greatest strength, immutability, is also it's greatest weakness. There are cases where you might need to update content on IPFS, but that would result in a new CID. IPCM (InterPlanetary CID Mapping) aims to solve this by storing a simple IPFS string onchain and letting the contract be the point of reference for the latest state. Benefits include:

  • Cryptographically secures ownership and updates to an onchain identity
  • Events create an onchain history of updates
  • Can be deployed to any EVM chain
  • Fetching the latest state is simple and fast

A simple example IPCM is for static webhosting on IPFS, where you can update the IPFS reference onchain without having to deal with the compliexities of IPNS. Check out the more detailed example below

sequenceDiagram
    participant User
    participant IPFS
    participant IPCM
    participant Reader

    User->>IPFS: Upload siteA.html
    IPFS-->>User: Return CID1
    User->>IPCM: Set state to ipfs://CID1
    User->>IPFS: Upload siteB.html
    IPFS-->>User: Return CID2
    User->>IPCM: Update state to ipfs://CID2
    Reader->>IPCM: Query latest state
    IPCM-->>Reader: Return ipfs://CID2
    Reader->>IPFS: Fetch CID2
    IPFS-->>Reader: Return html2.html content
Loading

Quick Start

Make sure you have Foundry already installed on your machine, more details here

Contract Deployment

Clone the GitHub repo and install dependencies

git clone https://github.com/PinataCloud/ipcm
cd ipcm
forge install

Deploy the contract in one command

forge create src/IPCM.sol:IPCM \
  --rpc-url <YOUR_CHAIN_RPC_URL> \
  --private-key <ACCOUNT_PRIVATE_KEY>

Tip

It is preferable to setup an account with cast or another secure method instead of using the private key in plain text. Please practice safe key management!

Optional: Verify the contract after deployment

forge v <CONTRACT_ADDRESS> \
  src/IPCM.sol:IPCM \
  -e <ETHERSCAN_API_KEY> \
  --rpc-url <YOUR_CHAIN_RPC_URL>

Contract Usage

After IPCM is deployed you can update the CID mapping using the updateMapping function and the library of your choice. Here is an example with Viem

import { account, publicClient, walletClient } from "./config";
import { abi } from "./ipcm_abi";

const { request } = await publicClient.simulateContract({
  account,
  address: "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
  abi: abi,
  functionName: "updateMapping", // Function to Update
  args: ["ipfs://bafkreigfakpjywuxaq57zhnnma6ntvs6u5p6eurgdl5kfkjvuhg6sztmda"], // IPFS CID args
});
await walletClient.writeContract(request);

Once a CID has been written to the contract, it can be fetched using the getMapping function.

import { publicClient } from "./client";
import { abi } from "./ipcm_abi";

const data = await publicClient.readContract({
  address: "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
  abi: abi,
  functionName: "getMapping",
});
// ipfs://bafkreigfakpjywuxaq57zhnnma6ntvs6u5p6eurgdl5kfkjvuhg6sztmda

With the CID reference you can render it into content using a tool like the IPFS SDK

import { publicClient } from "./client";
import { abi } from "./ipcm_abi";
import { PinataSDK } from "pinata-web3";

const pinata = new PinataSDK({
  pinataJwt: process.env.PINATA_JWT!,
  pinataGateway: "example-gateway.mypinata.cloud",
});

const cidMapping = await publicClient.readContract({
  address: "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
  abi: abi,
  functionName: "getMapping",
});

const { data, contentType } = await pinata.gateways.get(cidMapping);

Example Demo

The IPCM.dev website is an example of how IPCM can be used for static webhosting. It consists of a simple Cloudflare Worker that fetches the contract state each time a request is made and renders the content through an IPFS Gateway, creating a static proxy which only requires updating the onchian reference to update the site.

import { createPublicClient, http } from "viem";
import { baseSepolia } from "viem/chains";
import { abi } from "../utils/contract";
import { pinata } from "../utils/pinata";

export default {
  async fetch(
    request: Request,
    env: Env,
    ctx: ExecutionContext,
  ): Promise<Response> {
    try {
      const publicClient = createPublicClient({
        chain: baseSepolia,
        transport: http(),
      });

      const cid = await publicClient.readContract({
        address: "0x81FBD1886121f8575734808959DF808D19De170D",
        abi: abi,
        functionName: "getMapping",
      });

      if (!cid) {
        throw new Error(`Failed to fetch latest state: ${cid}`);
      }

      const url = await pinata.gateways.convert(cid as string);

      const response = await fetch(url);

      if (!response.ok) {
        throw new Error(`Failed to fetch from CDN: ${response.statusText}`);
      }

      const contentType = response.headers.get("content-type");

      return new Response(response.body, {
        status: 200,
        headers: {
          "Content-Type": contentType || "text/html",
          "Cache-Control": "public, max-age=3600",
        },
      });
    } catch (error) {
      console.error("Error:", error);
      return new Response(`Error: ${error}`, {
        status: 500,
        headers: { "Content-Type": "text/plain" },
      });
    }
  },
} satisfies ExportedHandler<Env>;

Questions and Feedback

IPCM is MIT licensed and open source; feedback and contributions are welcome! Please contact [email protected] with any questions you might have.

About

InterPlanetary CID Mapping Smart Contracts

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Solidity 100.0%