# InterPlanetary CID Mapping Source: https://github.com/PinataCloud/ipcm ## Summary IPCM (InterPlanetary CID Mapping) is a smart contract that stores an IPFS CID onchain, so the contract serves as a fixed reference point for the latest version of content that would otherwise change its CID. The article says it can be deployed to any EVM chain, that events create an onchain history of updates, and that fetching the latest state is simple and fast. For static webhosting, the IPCM.dev example uses a Cloudflare Worker that reads the contract on Base Sepolia and renders the referenced content through an IPFS gateway, so only the onchain reference needs updating to change the site. The project is MIT licensed and open source. ## Article InterPlanetary CID Mapping 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 \ --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 \ src/IPCM.sol:IPCM \ -e \ --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 onchain 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 { 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; Questions and Feedback IPCM is MIT licensed and open source; feedback and contributions are welcome! Please contact team@pinata.cloud with any questions you might have. ## Comments **mishaderidder.eth**: Interesting. Looks like this solves an important issue with IPFS. **mishaderidder.eth**: I have looked into this a bit more, and I think it does practically the same as using an ENS as IPNS. It would be practical if you would want to have a regular domain for your website on IPFS. **mishaderidder.eth**: (But I think you would still be depending on Cloudflare in the end. If you want to have an unstoppable website I think using ENS is preferable above this method.)