Skip to main content

Basic Example

Initializes a diamond proxy for an NFT system by wiring facets, owner data, metadata, and interface support.

Key Features
  • Registers facet function selectors for proxy routing via fallback.
  • Initializes ERC-173 owner storage.
  • Initializes ERC-721 metadata values (name, symbol, baseURI).
  • Registers ERC-165 support for IERC721 and IERC721Metadata.
  • Accepts transfers through receive().

Overview

ExampleDiamond is a minimal contract that initializes a diamond proxy for an NFT system by wiring facets, owner data, metadata, and interface support. It does not contain NFT business logic itself. Instead, it sets up routing and shared storage so NFT behavior implemented in facets can be reached through the diamond address.

During construction, it:

  1. Adds all facet selectors to the diamond selector mapping.
  2. Sets the initial Owner. (See OwnerDataFacet)
  3. Sets ERC-721 metadata values.
  4. Registers ERC-165 interface IDs for ERC-721 compatibility discovery.

After deployment, calls are routed through the contract fallback using selector lookup and delegatecall into facets.

Storage

This contract initializes state in multiple module-defined storage namespaces:

  • Diamond routing storage via DiamondMod (erc8153.diamond)
  • Owner storage via OwnerDataMod (erc173.owner)
  • ERC-721 metadata storage via ERC721MetadataMod (erc721.metadata)
  • ERC-165 support map via ERC165Mod (erc165)

Because modules use fixed storage locations, facets can safely share a single diamond storage context without slot collisions. See Shared Storage for more details.

Example Implementation

import "@perfect-abstractions/compose/diamond/DiamondMod.sol" as DiamondMod;
import "@perfect-abstractions/compose/access/Owner/Data/OwnerDataMod.sol" as OwnerDataMod;
import "@perfect-abstractions/compose/token/ERC721/Metadata/ERC721MetadataMod.sol" as ERC721MetadataMod;
import "@perfect-abstractions/compose/interfaceDetection/ERC165/ERC165Mod.sol" as ERC165Mod;
import {IERC721} from "@perfect-abstractions/compose/interfaces/IERC721.sol";
import {IERC721Metadata} from "@perfect-abstractions/compose/interfaces/IERC721Metadata.sol";

contract ExampleDiamond {
/**
* @notice Initializes the diamond contract with facets, owner and other data.
* @dev Adds all provided facets to the diamond's function selector mapping and sets the contract owner.
* Each facet in the array will have its function selectors registered to enable delegatecall routing.
* @param _facets Array of facet addresses and their corresponding function selectors to add to the diamond.
* @param _diamondOwner Address that will be set as the owner of the diamond contract.
*/
constructor(address[] memory _facets, address _diamondOwner) {
DiamondMod.addFacets(_facets);

/*************************************
* Initialize storage variables
************************************/

/**
* Setting the contract owner
*/
OwnerDataMod.setContractOwner(_diamondOwner);
/**
* Setting ERC721 token details
*/
ERC721MetadataMod.setMetadata({
_name: "ExampleDiamondNFT", _symbol: "EDN", _baseURI: "https://example.com/metadata/"
});
/**
* Registering ERC165 interfaces
*/
ERC165Mod.registerInterface(type(IERC721).interfaceId);
ERC165Mod.registerInterface(type(IERC721Metadata).interfaceId);
}

fallback() external payable {
DiamondMod.diamondFallback();
}

receive() external payable {}
}

This contract only initializes the diamond proxy.

Minting, transfers, approvals, and token ownership logic must come from their respective facets that you provide during deployment.

Best Practices

  • Deploy and test facets before passing them into the constructor.
  • Verify there are no selector collisions across facets.
  • Ensure facets expose the expected selectors format for registration.
  • Set _diamondOwner to a trusted account or governance contract.
Was this helpful?
Last updated:

Newsletter

Get notified about releases, feature announcements, and technical deep-dives on building smart contracts with Compose.

No spam. Unsubscribe anytime.