Skip to content

How to Deploy Diamond Contracts

Diamond contracts (EIP-2535) allow you to create modular, upgradeable contracts by organizing functionality into separate facets. This guide shows you how to deploy diamond contracts using hardhat-deploy.

Prerequisites

Install the diamond extension:

bash
npm install -D @rocketh/diamond
bash
pnpm add -D @rocketh/diamond

Add it to your rocketh/config.ts:

typescript
import * as diamondExtensions from '@rocketh/diamond';
import * as deployExtensions from '@rocketh/deploy';

const extensions = {...deployExtensions, ...diamondExtensions};

What are Diamond Contracts?

Diamond contracts consist of:

  • Diamond: The main contract that delegates calls to facets
  • Facets: Individual contracts containing specific functionality
  • Diamond Storage: Shared storage accessible by all facets
  • Diamond Cut: Mechanism to add, replace, or remove facets

Basic Diamond Deployment

Simple Diamond with Facets

typescript
import { deployScript, artifacts } from "../rocketh/deploy.js";

export default deployScript(
  async ({ diamond, namedAccounts }) => {
    const { deployer, admin } = namedAccounts;

    await diamond(
      "GreetingsRegistry", // Diamond name
      {
        account: deployer,
      },
      {
        facets: [
          { artifact: artifacts.GetMessageFacet },
          { artifact: artifacts.SetMessageFacet },
        ],
        facetsArgs: [
          {
            prefix: "Hello, ",
            num: 1,
          },
        ],
        owner: admin,
      }
    );
  },
  { tags: ["GreetingsRegistry", "diamond"] }
);

Upgrading Diamonds

When you modify a facet or add new ones, hardhat-deploy generates the appropriate diamondCut automatically:

typescript
import { deployScript, artifacts } from "../rocketh/deploy.js";

export default deployScript(
  async ({ diamond, namedAccounts }) => {
    const { deployer, admin } = namedAccounts;

    // When you add/modify facets, hardhat-deploy will:
    // - Detect new facets and add them
    // - Detect modified facets and replace them
    // - Detect removed facets and remove them
    await diamond(
      "GreetingsRegistry",
      {
        account: deployer,
      },
      {
        facets: [
          { artifact: artifacts.GetMessageFacet },
          { artifact: artifacts.SetMessageFacet },
          { artifact: artifacts.NewFeatureFacet }, // New facet added
        ],
        facetsArgs: [
          {
            prefix: "Hello, ",
            num: 2, // Updated argument
          },
        ],
        owner: admin,
      }
    );
  },
  { tags: ["GreetingsRegistry", "diamond"] }
);

Diamond Storage Pattern

When writing facets, use the diamond storage pattern to avoid storage collisions:

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library GreetingsStorage {
    bytes32 constant STORAGE_POSITION = keccak256("greetings.storage");

    struct Storage {
        string prefix;
        mapping(address => string) messages;
    }

    function get() internal pure returns (Storage storage s) {
        bytes32 position = STORAGE_POSITION;
        assembly {
            s.slot := position
        }
    }
}

Next Steps