---
eip: 8153
title: Facet-Based Diamonds
description: Simplifies diamond management, deployment and upgrades.
author: Nick Mudge (@mudgen)
discussions-to: https://ethereum-magicians.org/t/erc-8153-facet-based-diamonds/27685
status: Draft
type: Standards Track
category: ERC
created: 2026-02-07
requires: 2535
---
## Abstract

A diamond is a proxy contract that `delegatecall`s to multiple implementation contracts called facets. 

![Diagram showing how a diamond contract works](../assets/eip-8153/basic-diamond-diagram.svg)

Diamond contracts were originally standardized by [ERC-2535](./eip-2535). This ERC builds on that foundation by defining a facet-based architecture in which facets self-describe their function selectors through a standardized introspection interface.

By moving selector discovery on-chain, this approach eliminates the need for off-chain selector management. As a result, diamond deployment and upgrades become simpler, more deterministic, and more gas efficient.

This ERC introduces a facet introspection function, `exportSelectors()`, which every facet MUST implement. This function returns the list of function selectors implemented by the facet, allowing a diamond to discover and register selectors on-chain during deployment or upgrade.

This ERC also defines facet-based events for adding, replacing, and removing facets.

Additionally, the ERC also defines an optional `upgradeDiamond` function. This function uses `exportSelectors()` to automatically determine which selectors should be added, replaced, or removed when applying facet changes.

## Motivation

### Motivation for Diamond Contracts

<img alt="Obligatory diamond" src="../assets/eip-8153/diamond.svg" width="17%" align="right">Through a single contract address, a diamond provides functionality from multiple implementation contracts (facets). Each facet is independent, yet facets can share internal functions and storage. This architecture allows large smart-contract systems to be composed from separate facets and presented as a single contract, simplifying deployment, testing, and integration with other contracts, off-chain software, and user interfaces.

By decomposing large smart contracts into facets, diamonds can reduce complexity and make systems easier to reason about. Distinct areas of functionality can be isolated, organized, tested, and managed independently.

Diamonds combine the single-address convenience of a monolithic contract with the modular flexibility of distinct, integrated contracts.

This architecture is well suited to **immutable** smart-contract systems, where all functionality is composed from multiple facets at deployment time and permanently fixed thereafter.

For upgradeable systems, diamonds enable incremental development: new functionality can be added, and existing functionality modified, without redeploying unaffected facets.

Additional motivation and background for diamond-based smart-contract systems can be found in [ERC-1538](./eip-1538) and [ERC-2535](./eip-2535).

### Motivation for this Standard

In the past, deploying and upgrading diamonds suffered from:

1. **High gas costs**
2. **Function selector management complexity**
   Deploying or upgrading a diamond requires assembling function selectors off-chain. Since common tooling (e.g., Hardhat, Foundry) does not natively manage diamond selectors, developers rely on custom scripts or third-party libraries to handle diamond "plumbing".

This standard reduces gas costs and eliminates off-chain selector management:

* Diamonds become less expensive to deploy.
* Function selectors no longer need to be gathered off-chain.
* Standard deployment tools can be used without special diamond support.
* ERC-2535 introspection functions have simple implementations.

## Specification

### Terms
1. A **diamond** is a smart contract that routes external function calls to one or more implementation contracts, referred to as facets. A diamond is stateful: all persistent data is stored in the diamond’s contract storage. A diamond implements the requirements in the [Implementation Requirements](#implementation-requirements) section.
2. A **facet** is a smart contract that defines one or more external functions. A facet is deployed independently, and one or more of its functions are added to one or more diamonds. A facet’s functions are executed in the diamond’s context via `delegatecall`, so reads/writes affect the diamond’s storage. The term facet is derived from the diamond industry, referring to a flat surface of a diamond.
3. An **introspection function** is a function that returns information about the facets and/or functions used by a diamond or facet.
4. For the purposes of this specification, a **mapping** refers to a conceptual association between two items and does not refer to a specific implementation.

### Diamond Diagram

This diagram shows the structure of a diamond. 

It shows that a diamond has a mapping from function to facet and that facets can access the storage inside a diamond.

![Diagram showing structure of a diamond](../assets/eip-8153/functionFacetMapping.svg)

### Fallback

When an external function is called on a diamond, its fallback function is executed. The fallback function determines which facet to call based on the first four bytes of the calldata (known as the function selector) and executes the function from the facet using `delegatecall`.

A diamond’s fallback function and `delegatecall` enable a diamond to execute a facet’s function as if it was implemented by the diamond itself. The `msg.sender` and `msg.value` values do not change and only the diamond’s storage is read and written to.

Here is an example of how a diamond’s fallback function might be implemented:

```solidity
error FunctionNotFound(bytes4 _selector);

// Executes function call on facet using `delegatecall`.
// Returns function call return data or revert data.
fallback() external payable {
    // Get facet address from function selector
    address facet = selectorToFacet[msg.sig];
    if (facet == address(0)) {
        revert FunctionNotFound(msg.sig);
    }
    // Execute external function on facet using `delegatecall` and return any value.
    assembly {
        // Copy function selector and any arguments from calldata to memory.
        calldatacopy(0, 0, calldatasize())
        // Execute function call using the facet.
        let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
        // Copy all return data from the previous call into memory.
        returndatacopy(0, 0, returndatasize())
        // Return any return value or error back to the caller.
        switch result
        case 0 {revert(0, returndatasize())}
        default {return (0, returndatasize())}
    }
}
```
#### Function Not Found

If the fallback function cannot find a facet for a function selector, and there is no default function or other mechanism to handle the call, the fallback MUST revert with the error `FunctionNotFound(bytes4 _selector)`.

### Inspecting Diamonds

An [ERC-8153](./eip-8153) diamond MUST implement the same introspection functions as defined in ERC-2535.
Specifically, these functions MUST be implemented:

```solidity
interface IDiamondInspect {
    struct Facet {
        address facetAddress;
        bytes4[] functionSelectors;
    }

    /// @notice Gets all facet addresses and their four byte function selectors.
    /// @return facets_ Facet
    function facets() external view returns (Facet[] memory facets_);

    /// @notice Gets all the function selectors supported by a specific facet.
    /// @param _facet The facet address.
    /// @return facetFunctionSelectors_
    function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_);

    /// @notice Get all the facet addresses used by a diamond.
    /// @return facetAddresses_
    function facetAddresses() external view returns (address[] memory facetAddresses_);

    /// @notice Gets the facet that supports the given selector.
    /// @dev If facet is not found return address(0).
    /// @param _functionSelector The function selector.
    /// @return facetAddress_ The facet address.
    function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);
}
```

Typically, these functions are implemented in a facet and the facet is added to diamonds.

### Inspecting Facets

Each facet MUST implement the following pure introspection function:

```solidity
function exportSelectors() external pure returns (bytes memory selectors)
```

`exportSelectors()` returns a `bytes` array containing one or more 4-byte function selectors. The returned `bytes` array length is a multiple of 4, and each 4-byte chunk is a selector. The function MUST not return the same selector more than once.

The `bytes` array contains selectors of functions implemented by the facet that are intended to be added to a diamond.

This enables a diamond to discover selectors directly from facets at deployment or upgrade time. A diamond calls `exportSelectors()` on each facet to determine which selectors to add, replace, or remove.

Selector gathering is therefore no longer an off-chain responsibility.

This also means diamonds implementing this ERC are **facet-based** rather than **function-based**. Deployment and upgrades operate on facets.

### Facet-Based Events

This ERC replaces ERC-2535’s function-based events with facet-based events. 

When facets are added, replaced, or removed, the diamond MUST emit the following events:

```solidity
 /**
  * @notice Emitted when a facet is added to a diamond.
  * @dev The function selectors this facet handles can be retrieved by calling
  *      `IFacet(_facet).exportSelectors()`
  *
  * @param _facet The address of the facet that handles function calls to the diamond.
  */
event FacetAdded(address indexed _facet);

/**
 * @notice Emitted when an existing facet is replaced with a new facet.
 * @dev
 * - Selectors that are present in the new facet but not in the old facet are added to the diamond.
 * - Selectors that are present in both the new and old facet are updated to use the new facet.
 * - Selectors that are not present in the new facet but are present in the old facet are removed from
 *   the diamond.
 *
 * The function selectors handled by these facets can be retrieved by calling:
 * - `IFacet(_oldFacet).exportSelectors()`
 * - `IFacet(_newFacet).exportSelectors()`
 *
 * @param _oldFacet The address of the facet that previously handled function calls to the diamond.
 * @param _newFacet The address of the facet that now handles function calls to the diamond.
 */
event FacetReplaced(address indexed _oldFacet, address indexed _newFacet);

/**
 * @notice Emitted when a facet is removed from a diamond.
 * @dev The function selectors this facet handles can be retrieved by calling
 *      `IFacet(_facet).exportSelectors()`
 *
 * @param _facet The address of the facet that previously handled function calls to the diamond.
 */
event FacetRemoved(address indexed _facet);
```

Block explorers and other tooling can obtain the function selectors for any of the facets referenced by these events by calling `exportSelectors()` on the facet address.

### Optional Upgrade Events

#### Recording Non-Fallback `delegatecall`s

This event is OPTIONAL.

This event can be used to record `delegatecall`s made by a diamond.

This event MUST NOT be emitted for `delegatecall`s made by a diamond’s fallback function when routing calls to facets. It is only intended for `delegatecall`s made by functions in facets or a diamond’s constructor.

This event enables tracking of changes to a diamond’s contract storage caused by `delegatecall` execution.

```solidity
/**
* @notice Emitted when a diamond's constructor function or function from a
*         facet makes a `delegatecall`. 
* 
* @param _delegate         The contract that was the target of the `delegatecall`.
* @param _delegateCalldata The function call, including function selector and 
*                          any arguments.
*/
event DiamondDelegateCall(address indexed _delegate, bytes _delegateCalldata);
```

#### Diamond Metadata

This event is OPTIONAL.

This event can be used to record versioning or other information about diamonds.

It can be used to record information about diamond upgrades.

```solidity
/**
* @notice Emitted to record information about a diamond.
* @dev    This event records any arbitrary metadata. 
*         The format of `_tag` and `_data` are not specified by the 
*         standard.
*
* @param _tag   Arbitrary metadata, such as a release version.
* @param _data  Arbitrary metadata.
*/
event DiamondMetadata(bytes32 indexed _tag, bytes _data);
```

### Implementation Requirements

A facet-based diamond MUST implement the following:

1. **Diamond Structure**
   - A `fallback()` function.
2. **Function Association**
   - It MUST associate function selectors with facet addresses.
3. **Function Execution**
   - When an external function is called on a diamond:
     - The diamond’s fallback function is executed. 
     - The fallback function MUST find the facet associated with the function selector.
     - The fallback function MUST execute the function on the facet using `delegatecall`.
     - If no facet is associated with the function selector, the diamond MAY execute a default function or apply another handling mechanism.
     - If no facet, default function, or other handling mechanism exists, execution MUST revert with the error `FunctionNotFound(bytes4 _selector)`.
4. **Events**
   - The following events MUST be emitted:
     - `FacetAdded` — when a facet is added to a diamond.
     - `FacetReplaced` — when a facet is replaced with a different facet.
     - `FacetRemoved` — when a facet is removed from a diamond.
5. **Diamond Introspection**
   - A diamond MUST implement the following introspection functions:
     - `facets()`
     - `facetFunctionSelectors(address _facet)`
     - `facetAddresses()`
     - `facetAddress(bytes4 _functionSelector)`
6. **Facet Introspection**
   - Each facet MUST implement the `exportSelectors()` function, which returns a `bytes` array.


### `receive()` function

A diamond MAY have a `receive()` function.

### `upgradeDiamond` Function

Implementing `upgradeDiamond` is OPTIONAL.

This function is specified for interoperability with tooling (e.g., GUIs and command-line tools) so that upgrades can be executed with consistent and predictable behavior.

`upgradeDiamond` adds, replaces, and removes any number of facets in a single transaction. It can also optionally execute a `delegatecall` to perform initialization or state migration.

The `upgradeDiamond` function works as follows:

#### Adding a Facet

1. Call `exportSelectors()` on the facet to obtain its function selectors. 
2. Add each selector to the diamond, mapping it to the facet address.

#### Replacing a Facet

1. Call `exportSelectors()` on the old facet to obtain its packed selectors.
2. Call `exportSelectors()` on the new facet to obtain its packed selectors.
3. For selectors present in the new facet but not the old facet: add them.
4. For selectors present in both: replace them to point to the new facet.
5. For selectors present in the old facet but not the new facet: remove them.

#### Removing a Facet
1. Call `exportSelectors()` on the facet to obtain its packed selectors.
2. Remove each selector from the diamond.

#### Errors and Types

```solidity
/**
 * @notice The upgradeDiamond function below detects and reverts
 *         with the following errors.
 */
error NoSelectorsForFacet(address _facet);
error NoBytecodeAtAddress(address _contractAddress);
error CannotAddFunctionToDiamondThatAlreadyExists(bytes4 _selector);
error CannotRemoveFacetThatDoesNotExist(address _facet);
error CannotReplaceFacetWithSameFacet(address _facet);
error FacetToReplaceDoesNotExist(address _oldFacet);
error DelegateCallReverted(address _delegate, bytes _delegateCalldata);
error ExportSelectorsCallFailed(address _facet);

/**
 * @dev This error means that a function to replace exists in a
 *      facet other than the facet that was given to be replaced.
 */
error CannotReplaceFunctionFromNonReplacementFacet(bytes4 _selector);

/**
 * @notice This struct is used to replace old facets with new facets.
 */
struct FacetReplacement {
    address oldFacet;
    address newFacet;
}
```

#### Function Signature

```solidity
/**
 * @notice Upgrade the diamond by adding, replacing, or removing facets.
 *
 * @dev
 * Facets are added first, then replaced, then removed.
 *
 * These events are emitted to record changes to facets:
 * - `FacetAdded(address indexed _facet)`
 * - `FacetReplaced(address indexed _oldFacet, address indexed _newFacet)`
 * - `FacetRemoved(address indexed _facet)`
 *
 * If `_delegate` is non-zero, the diamond performs a `delegatecall` to
 * `_delegate` using `_delegateCalldata`. The `DiamondDelegateCall` event is
 *  emitted.
 *
 * The `delegatecall` is done to alter a diamond's state or to
 * initialize, modify, or remove state after an upgrade.
 *
 * However, if `_delegate` is zero, no `delegatecall` is made and no
 * `DiamondDelegateCall` event is emitted.
 *
 * If _tag is non-zero or if _metadata.length > 0 then the
 * `DiamondMetadata` event is emitted.
 *
 * @param _addFacets        Facets to add.
 * @param _replaceFacets    (oldFacet, newFacet) pairs, to replace old with new.
 * @param _removeFacets     Facets to remove.
 * @param _delegate         Optional contract to delegatecall (zero address to skip).
 * @param _delegateCalldata Optional calldata to execute on `_delegate`.
 * @param _tag              Optional arbitrary metadata, such as release version.
 * @param _metadata         Optional arbitrary data.
 */
function upgradeDiamond(
    address[] calldata _addFacets,
    FacetReplacement[] calldata _replaceFacets,
    address[] calldata _removeFacets,
    address _delegate,
    bytes calldata _delegateCalldata,
    bytes32 _tag,
    bytes calldata _metadata
);
```
The `upgradeDiamond` function MUST adhere to the following requirements:

> The complete definitions of events and custom errors referenced below are given earlier in this standard.

1. **Inputs**
   - `_addFacets` array of facet addresses to add.
   - `_replaceFacets` array of (`oldFacet`, `newFacet`) pairs.
   - `_removeFacets` array of facet addresses to remove.

2. **Execution Order**
   1. Add facets
   2. Replace facets
   3. Remove facets

3. **Event Emission**
   - Every change to a facet MUST emit exactly one of:
     - `FacetAdded`
     - `FacetReplaced`
     - `FacetRemoved`

4. **Error Conditions**
   - The implementation MUST detect and revert with the specified error when:
     - Adding a selector that already exists: `CannotAddFunctionToDiamondThatAlreadyExists`.
     - Removing a facet that does not exist: `CannotRemoveFacetThatDoesNotExist`.
     - Replacing a facet with itself: `CannotReplaceFacetWithSameFacet`.
     - Replacing a facet that does not exist: `FacetToReplaceDoesNotExist`.
     - Replacing a selector that exists in the diamond but is mapped to a facet different than the facet being replaced: `CannotReplaceFunctionFromNonReplacementFacet`.

5. **Facet Validation**
   - If any facet address contains no contract bytecode, revert with `NoBytecodeAtAddress`.
   - If `exportSelectors()` is missing, reverts, or cannot be called successfully, revert with `ExportSelectorsCallFailed`.
   - If `exportSelectors()` returns zero selectors, revert with `NoSelectorsForFacet`.

6. **Delegate Validation**
   - If `_delegate` is non-zero but contains no bytecode, revert with `NoBytecodeAtAddress`.

7. **Delegatecall Execution**
   - If `_delegate` is non-zero, the diamond MUST `delegatecall` `_delegate` with `_delegateCalldata`.
   - If the `delegatecall` fails and returns revert data, the diamond MUST revert with the same revert data.
   - If the `delegatecall` fails and returns no revert data, revert with `DelegateCallReverted`.
   - If a `delegatecall` is performed, the diamond MUST emit the `DiamondDelegateCall` event.
   - `_delegateCalldata` MAY be empty. If empty, the `delegatecall` executes with no calldata.

8. **Metadata Event**
   - If `_tag` is non-zero or `_metadata.length > 0`, the diamond MUST emit the `DiamondMetadata` event.

After adding, replacing, or removing facets, the diamond MAY perform a `delegatecall` to initialize, migrate, or clean up state.

It is also valid to call `upgradeDiamond` solely to perform a `delegatecall` (i.e., without adding, replacing, or removing any facets).

To skip an operation, supply an empty array for its parameter (for example, `new address[](0)` for `_addFacets`).

## Rationale

### Eliminating Selector Management

To deploy a facet-based diamond implementing this ERC, the deployer provides an array of facet addresses to the diamond constructor. The constructor calls `exportSelectors()` on each facet and registers those selectors in the diamond.

Because facets self-describe their selectors, deployers no longer need to gather selectors off-chain or depend on specialized selector tooling.

### Reducing Deployment Gas Costs

#### Reducing Calldata

In a non-facet-based diamond, selectors are typically passed to the constructor as one or more `bytes4[]` arrays. These arrays are paid for in calldata and then copied into memory, incurring additional gas.

In a facet-based diamond, only facet addresses are passed to constructors. The diamond calls `exportSelectors()` on each facet to obtain selectors on-chain, avoiding calldata costs for selector lists. While calling `exportSelectors()` introduces some overhead, non-facet-based diamonds typically perform code-existence checks (e.g., `extcodesize`) on facet addresses anyway, incurring the cold account access gas cost.

#### Reducing Storage

In a **non-facet-based diamond**, function selectors are stored directly for introspection, typically in a `bytes4[] selectors` array (or an equivalent structure). Because a storage slot is 32 bytes, each slot can hold up to eight `bytes4` selectors. As more functions are added, additional storage slots are required, so storage usage grows linearly with the number of selectors.

In a **facet-based diamond**, introspection data can be stored **per facet instead of per function**. Each facet only needs a single representative selector. This means one 32-byte storage slot can represent up to eight facets, regardless of how many function selectors each facet implements. Storage usage therefore grows with the number of facets, not the number of functions.

Alternatively, a facet-based diamond can be implemented as a **linked list of facets**. With this design, introspection requires a **single 32-byte storage slot**, while supporting any number of facets and any number of selectors per facet.

### `exportSelectors()` Function Return Value

`exportSelectors()` returns `bytes` rather than `bytes4[]` for two reasons:

#### `bytes4[]` Wastes Memory

Each element of a `bytes4[]` array occupies 32 bytes in memory, but only 4 bytes are meaningful. This wastes 87.5% of allocated memory, increasing gas costs. Packing selectors into `bytes` reduces memory overhead.

#### Simple Syntax For Facets

Facets can implement `exportSelectors()` concisely using Solidity's built-in function `bytes.concat`. Example:

```solidity
function exportSelectors() external pure returns (bytes memory) {
    return bytes.concat(
        this.facetAddress.selector,
        this.facetFunctionSelectors.selector,
        this.facetAddresses.selector,
        this.facets.selector
    );
}
```

The diamond can traverse the returned bytes and extract selectors efficiently.

### Diamond Upgrades

This upgrade function specified by this standard is optional.

This means a couple things:

#### 1. Diamonds Can Be Immutable

A Diamond does not have to have an upgrade function.

- A diamond can be fully constructed within its constructor function without adding any upgrade function, making it immutable upon deployment.

- A large immutable diamond can be built using well organized facets.

- A diamond can initially be upgradeable, and later made immutable by removing its upgrade function.

#### 2. You Can Create Your Own Upgrade Functions

You can design and create your own upgrade functions and remain compliant with this standard. All that is required is that you emit the appropriate add/replace/remove required events specified in the [Facet-Based Events section](#facet-based-events), that the introspection functions defined in the [Inspecting Diamonds section](#inspecting-diamonds) and the [Inspecting Facets section](#inspecting-facets) continue to exists and accurately return function and facet information.

### Runtime Gas Considerations

Routing calls via `delegatecall` introduces a small amount of gas overhead. In practice, this cost is mitigated by several architectural and tooling advantages enabled by diamonds:

1. **Optional, gas-optimized functionality**  
   By structuring functionality across multiple facets, diamonds make it straightforward to include specialized, gas-optimized features without increasing the complexity of core logic.  
   For example, an [ERC-721](./eip-721.md) diamond may implement batch transfer functions in a dedicated facet, improving both gas efficiency and usability while keeping the base ERC-721 implementation simple and well-scoped.

2. **Reduced external call overhead**    
   Some contract architectures require multiple external calls within a single transaction. By consolidating related functionality behind a single diamond address, these interactions can execute internally with shared storage and shared authorization, reducing gas costs from external calls and repeated access-control checks.  

3. **Selective optimization per facet**  
   Because facets are compiled and deployed independently, they may be built with different compiler optimizer settings. This allows gas-critical facets to use aggressive optimization configurations to reduce execution costs, without increasing bytecode size or compilation complexity for unrelated functionality.

### Storage Layout

Diamonds and facets need to use a storage layout organizational pattern because Solidity’s default storage layout doesn’t support proxy contracts or diamonds. The storage layout technique or pattern to use is not specified in this ERC. However, examples of storage layout patterns that work with diamonds are [ERC-8042 Diamond Storage](./eip-8042) and [ERC-7201 Namespaced Storage Layout](./eip-7201).

### Facets Sharing Storage & Functionality

Facets are separately deployed, independent units, but can share state and functionality in the following ways:

- Facets can share state variables by using the same structs at the same storage positions. 
- Facets can share internal functions by importing them or inheriting contracts. 

### On-chain Facets can be Reused and Composed

A deployed facet can be used by many diamonds.

It is possible to create and deploy a set of facets that are reused by different diamonds.

The ability to use the same deployed facets for many diamonds has the potential to reduce development time, increase reliability and security, and reduce deployment costs.

It is possible to implement facets in a way that makes them usable/composable/compatible with other facets. 

## Backwards Compatibility

Diamonds implementing this ERC have the same introspection functions as ERC-2535 diamonds, so they are compatible with ERC-2535 tooling that rely on these functions.

## Security Considerations

### Arbitrary Execution with `upgradeDiamond`

The `upgradeDiamond` function allows arbitrary execution with access to the diamond’s storage (through delegatecall). Access to this function must be restricted carefully.

### Use Only Trusted and Verified Facets

Only trusted and verified facets should be added to facet-based diamonds.

`exportSelectors()` MUST be `pure` and should not contain logic that varies the returned bytes. Facets should be immutable so returned selectors cannot change over time.

If a facet’s `exportSelectors()` output changes, upgrades that rely on it may add/remove/replace the wrong selectors and corrupt diamonds.

### Upgrade Integrity Checks

The specified `upgradeDiamond` behavior prevents a number of upgrade mistakes. Upgrades revert when:

- A facet is added that already exists in the diamond.
- A facet is replaced or removed that does not exist in the diamond.
- A selector is added that already exists in the diamond.
- A selector is replaced that exists in the diamond but it is from a different facet than the facet being replaced.
- A facet address contains no bytecode.
- A facet does not implement `exportSelectors()` successfully.
- A facet provides zero selectors.
- A facet is replaced with itself (same contract address).

Selector collisions (two different signatures with the same 4-byte selector) are handled as “selector already exists” and are therefore prevented.

### Do Not Self Destruct
Use of selfdestruct in a facet is heavily discouraged. Misuse of it can delete a diamond or a facet.

### Transparency

A diamond emits an event every time a facet is added, replaced or removed. Source code can be verified. This enables people and software to monitor changes to a diamond. 

Security and domain experts can review a diamond's upgrade history.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
