Skip to main content
The DiamondCutFacet implements the EIP-2535 Diamond Standard’s upgrade mechanism, allowing the diamond contract to be upgraded by adding new facets, replacing existing ones, or removing facets.

Functions

diamondCut

Performs a diamond cut to modify the diamond’s facets.
function diamondCut(
  _diamondCut: LibDiamond.FacetCutStruct[],
  _init: string,
  _calldata: BytesLike
): Promise<ContractTransaction>
_diamondCut
LibDiamond.FacetCut[]
required
Array of FacetCut structs describing the changes to make
_init
address
required
Address of the contract to call after the cut (use zero address to skip)
_calldata
bytes
required
Calldata to pass to the _init contract (empty if _init is zero address)

Data Structures

LibDiamond.FacetCut

Describes a single facet modification.
facetAddress
address
required
Address of the facet contract
action
uint8
required
Action to perform:
  • 0 = Add: Add new functions from the facet
  • 1 = Replace: Replace existing functions with new implementations
  • 2 = Remove: Remove functions (facetAddress must be zero address)
functionSelectors
bytes4[]
required
Array of function selectors to add, replace, or remove

Events

DiamondCut

Emitted when a diamond cut is performed.
_diamondCut
LibDiamond.FacetCut[]
Array of facet cuts that were applied
_init
address
Address of initialization contract called
_calldata
bytes
Calldata passed to initialization contract

Usage Examples

Adding a New Facet

import { DiamondCutFacet__factory } from '@lifi/contract-types';
import { ethers } from 'ethers';

const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const signer = provider.getSigner();
const diamondCut = DiamondCutFacet__factory.connect(DIAMOND_ADDRESS, signer);

const FacetCutAction = {
  Add: 0,
  Replace: 1,
  Remove: 2
};

// Deploy new facet
const NewFacet = await ethers.getContractFactory('NewFacet');
const newFacet = await NewFacet.deploy();
await newFacet.deployed();

// Get function selectors from the new facet
const selectors = Object.keys(newFacet.interface.functions)
  .map(fn => newFacet.interface.getSighash(fn));

// Prepare the diamond cut
const cut = [{
  facetAddress: newFacet.address,
  action: FacetCutAction.Add,
  functionSelectors: selectors
}];

// Execute the cut
const tx = await diamondCut.diamondCut(
  cut,
  ethers.constants.AddressZero, // No initialization
  '0x' // No calldata
);
await tx.wait();

Replacing Functions

// Deploy updated facet
const UpdatedFacet = await ethers.getContractFactory('UpdatedFacet');
const updatedFacet = await UpdatedFacet.deploy();
await updatedFacet.deployed();

// Select which functions to replace
const selectorsToReplace = [
  updatedFacet.interface.getSighash('functionToUpdate'),
  updatedFacet.interface.getSighash('anotherFunctionToUpdate')
];

const cut = [{
  facetAddress: updatedFacet.address,
  action: FacetCutAction.Replace,
  functionSelectors: selectorsToReplace
}];

const tx = await diamondCut.diamondCut(
  cut,
  ethers.constants.AddressZero,
  '0x'
);
await tx.wait();

Removing Functions

// Remove specific functions
const selectorsToRemove = [
  '0x12345678', // Function selector to remove
  '0x87654321'  // Another selector to remove
];

const cut = [{
  facetAddress: ethers.constants.AddressZero, // Must be zero for Remove action
  action: FacetCutAction.Remove,
  functionSelectors: selectorsToRemove
}];

const tx = await diamondCut.diamondCut(
  cut,
  ethers.constants.AddressZero,
  '0x'
);
await tx.wait();

Diamond Cut with Initialization

// Deploy initialization contract
const DiamondInit = await ethers.getContractFactory('DiamondInit');
const diamondInit = await DiamondInit.deploy();
await diamondInit.deployed();

// Encode initialization function call
const initCalldata = diamondInit.interface.encodeFunctionData('init', [
  // initialization parameters
]);

const cut = [{
  facetAddress: newFacet.address,
  action: FacetCutAction.Add,
  functionSelectors: selectors
}];

// Execute cut with initialization
const tx = await diamondCut.diamondCut(
  cut,
  diamondInit.address,
  initCalldata
);
await tx.wait();

Batch Operations

// Add, replace, and remove in a single transaction
const cuts = [
  {
    facetAddress: newFacet.address,
    action: FacetCutAction.Add,
    functionSelectors: newSelectors
  },
  {
    facetAddress: updatedFacet.address,
    action: FacetCutAction.Replace,
    functionSelectors: selectorsToReplace
  },
  {
    facetAddress: ethers.constants.AddressZero,
    action: FacetCutAction.Remove,
    functionSelectors: selectorsToRemove
  }
];

const tx = await diamondCut.diamondCut(
  cuts,
  ethers.constants.AddressZero,
  '0x'
);
await tx.wait();

Security Considerations

  • Only authorized addresses (typically the diamond owner) can execute diamond cuts
  • Diamond cuts are irreversible - test thoroughly on testnets first
  • Be careful when removing functions that other facets depend on
  • The initialization contract is called with delegatecall, so it operates in the diamond’s storage context
  • Always verify facet addresses and selectors before executing cuts

Build docs developers (and LLMs) love