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/diamondbash
pnpm add -D @rocketh/diamondAdd 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
- Deploy with Proxies for alternative upgrade patterns
- Deployment Fixtures in Tests for testing diamond contracts