Full EIP-2535 diamond pattern implementation with automatic facet management, upgrade detection, and deterministic deployment support.
Deploy diamond contracts with facet management and automatic upgrade handling.
/**
* Deploy a diamond contract with specified facets
* @param name - Diamond deployment name
* @param options - Diamond deployment configuration
* @returns Promise resolving to deployment result
*/
diamond: {
deploy(name: string, options: DiamondOptions): Promise<DeployResult>;
}
interface DiamondOptions extends TxOptions {
/** Owner address for the diamond */
owner?: Address;
/** Array of facets to deploy/configure */
facets: DiamondFacets;
/** Custom diamond contract to use as base */
diamondContract?: string | ArtifactData;
/** Diamond constructor arguments */
diamondContractArgs?: any[];
/** Include default DiamondCutFacet */
defaultCutFacet?: boolean;
/** Include default OwnershipFacet */
defaultOwnershipFacet?: boolean;
/** Include default DiamondLoupeFacet */
defaultLoupeFacet?: boolean;
/** Initialization execution after deployment */
execute?: {
contract?:
| string
| { name: string; artifact: string | ArtifactData; args?: any[] };
methodName: string;
args: any[];
};
/** Exclude specific selectors from facets */
excludeSelectors?: {
[facetName: string]: string[];
};
/** Salt for deterministic diamond deployment */
deterministicSalt?: string;
/** Constructor arguments for all facets */
facetsArgs?: any[];
/** Libraries for linking */
libraries?: Libraries;
/** Additional data for tracking */
linkedData?: any;
/** Upgrade tracking index */
upgradeIndex?: number;
}Usage Examples:
import { deployments, getNamedAccounts } from "hardhat";
// Basic diamond deployment
const { deployer } = await getNamedAccounts();
await deployments.diamond.deploy("GameDiamond", {
from: deployer,
owner: deployer,
facets: [
"PlayerFacet",
"InventoryFacet",
"BattleFacet",
],
});
// Diamond with custom facet configurations
await deployments.diamond.deploy("AdvancedDiamond", {
from: deployer,
owner: deployer,
facets: [
{
name: "CustomPlayerFacet",
contract: "PlayerFacetV2",
args: ["player", "init", "args"],
},
{
name: "InventoryFacet",
deterministic: true,
},
"BattleFacet", // Simple string facet
],
execute: {
methodName: "initialize",
args: ["diamond", "initialization"],
},
});
// Diamond with excluded selectors
await deployments.diamond.deploy("SelectiveDiamond", {
from: deployer,
owner: deployer,
facets: ["ComprehensiveFacet"],
excludeSelectors: {
ComprehensiveFacet: ["deprecatedFunction()", "internalFunction()"],
},
});Configure individual facets with specific deployment options and arguments.
type DiamondFacets = Array<string | FacetOptions>;
interface FacetOptions {
/** Custom name for the facet deployment */
name?: string;
/** Contract artifact name or data */
contract?: string | ArtifactData;
/** Constructor arguments for this facet */
args?: any[];
/** Additional data for this facet */
linkedData?: any;
/** Libraries for this facet */
libraries?: Libraries;
/** Enable deterministic deployment */
deterministic?: boolean | string;
}Usage Examples:
// Mixed facet configuration
await deployments.diamond.deploy("FlexibleDiamond", {
from: deployer,
owner: deployer,
facets: [
// Simple string facet
"CoreFacet",
// Facet with custom configuration
{
name: "ConfigurableFacet",
contract: "AdvancedFacet",
args: ["custom", "constructor", "args"],
deterministic: true,
},
// Facet with libraries
{
name: "LibraryFacet",
contract: "FacetWithLibrary",
libraries: {
MathLib: "0x1234567890123456789012345678901234567890",
},
},
// Facet with custom artifact
{
name: "CustomFacet",
contract: {
abi: [...], // Custom ABI
bytecode: "0x...", // Custom bytecode
},
args: [],
},
],
});
// Deterministic facet deployment
await deployments.diamond.deploy("DeterministicDiamond", {
from: deployer,
owner: deployer,
deterministicSalt: "0x1234567890123456789012345678901234567890123456789012345678901234",
facets: [
{
name: "FacetA",
deterministic: "0x1111111111111111111111111111111111111111111111111111111111111111",
},
{
name: "FacetB",
deterministic: true, // Uses default salt
},
],
});Automatic facet upgrade detection and diamond cut execution.
Usage Examples:
// Upgrade tracking
await deployments.diamond.deploy("UpgradeableDiamond", {
from: deployer,
owner: deployer,
upgradeIndex: 2, // Only upgrade if current version < 2
facets: [
"FacetV1",
"FacetV2", // New facet for upgrade
],
});
// Post-upgrade execution
await deployments.diamond.deploy("InitializableDiamond", {
from: deployer,
owner: deployer,
facets: ["DataFacet", "LogicFacet"],
execute: {
contract: {
name: "DiamondInit",
artifact: "InitializationContract",
args: ["init", "contract", "args"],
},
methodName: "init",
args: ["post", "upgrade", "data"],
},
});
// Custom diamond base contract
await deployments.diamond.deploy("CustomBaseDiamond", {
from: deployer,
owner: deployer,
diamondContract: "MyCustomDiamond",
diamondContractArgs: ["{owner}", "{facetCuts}", "{init}"],
facets: ["MyFacet"],
});Control default facets and selector exclusions.
Usage Examples:
// Minimal diamond (no default facets)
await deployments.diamond.deploy("MinimalDiamond", {
from: deployer,
owner: deployer,
defaultCutFacet: false,
defaultOwnershipFacet: false,
defaultLoupeFacet: true, // Keep only loupe for introspection
facets: ["BusinessLogicFacet"],
});
// Diamond with selector exclusions
await deployments.diamond.deploy("FilteredDiamond", {
from: deployer,
owner: deployer,
facets: [
"MultiFunctionFacet",
"AnotherFacet",
],
excludeSelectors: {
MultiFunctionFacet: [
"dangerousFunction()",
"deprecatedFunction(uint256)",
],
AnotherFacet: [
"internalHelper()",
],
},
});
// Global facet arguments
await deployments.diamond.deploy("UniformDiamond", {
from: deployer,
owner: deployer,
facetsArgs: ["shared", "constructor", "args"], // Used by all facets
facets: [
"FacetA", // Will use facetsArgs
"FacetB", // Will use facetsArgs
{
name: "FacetC",
args: ["custom", "args"], // Overrides facetsArgs
},
],
});interface DiamondOptions extends TxOptions {
owner?: Address;
facets: DiamondFacets;
diamondContract?: string | ArtifactData;
diamondContractArgs?: any[];
defaultCutFacet?: boolean;
defaultOwnershipFacet?: boolean;
execute?: {
contract?:
| string
| { name: string; artifact: string | ArtifactData; args?: any[] };
methodName: string;
args: any[];
};
excludeSelectors?: {
[facetName: string]: string[];
};
deterministicSalt?: string;
facetsArgs?: any[];
libraries?: Libraries;
linkedData?: any;
upgradeIndex?: number;
}
type DiamondFacets = Array<string | FacetOptions>;
interface FacetOptions {
name?: string;
contract?: string | ArtifactData;
args?: any[];
linkedData?: any;
libraries?: Libraries;
deterministic?: boolean | string;
}
interface Facet {
facetAddress: string;
functionSelectors: string[];
}
interface FacetCut extends Facet {
action: FacetCutAction;
}
enum FacetCutAction {
Add,
Replace,
Remove,
}
interface TxOptions extends CallOptions {
from: string;
log?: boolean;
autoMine?: boolean;
estimatedGasLimit?: string | number | BigNumber;
estimateGasExtra?: string | number | BigNumber;
waitConfirmations?: number;
}
type Libraries = { [libraryName: string]: Address };
type Address = string;
type ABI = any[];