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
Address of the contract to call after the cut (use zero address to skip)
Calldata to pass to the _init contract (empty if _init is zero address)
Data Structures
LibDiamond.FacetCut
Describes a single facet modification.
Address of the facet contract
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)
Array of function selectors to add, replace, or remove
Events
DiamondCut
Emitted when a diamond cut is performed.
Array of facet cuts that were applied
Address of initialization contract called
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