Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revise EIP-2535 #5120

Closed
wants to merge 11 commits into from
98 changes: 46 additions & 52 deletions EIPS/eip-2535.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,37 @@ eip: 2535
title: Diamonds, Multi-Facet Proxy
author: Nick Mudge (@mudgen)
Pandapip1 marked this conversation as resolved.
Show resolved Hide resolved
discussions-to: https://github.com/ethereum/EIPs/issues/2535
status: Last Call
last-call-deadline: 2020-08-15
status: Review
description: A standard for creating modular smart contract systems that can be extended after deployment
type: Standards Track
category: ERC
created: 2020-02-22
requires: 1538, 2535
Pandapip1 marked this conversation as resolved.
Show resolved Hide resolved
---

<img align="right" src="../assets/eip-2535/diamond.svg" width="230" height="230">

## Simple Summary
Pandapip1 marked this conversation as resolved.
Show resolved Hide resolved

Standard for creating modular smart contract systems that can be extended after deployment.
## Abstract
<img align="right" src="../assets/eip-2535/diamond.svg" width="230" height="230">

Enables people to write smart contracts with virtually no size limit.
This EIP proposes a standard for creating modular smart contract systems that can be extended after deployment ("Diamonds"). This enables smart contracts to effectively have no size limit, and to be upgraded without having to redeploy existing functionality. A Diamond's "Facets" can be added, replaced, or removed without having to worry about unintended side-effects, providing a layer of abstraction that aids development.
Pandapip1 marked this conversation as resolved.
Show resolved Hide resolved

Diamonds can be upgraded without having to redeploy existing functionality. Parts of a diamond can be added/replaced/removed while leaving other parts alone.
## Motivation

Standardizes contract interfaces and implementation details of diamonds, enabling software integration and interoperability.
There are a number of different reasons to use diamonds. Here are some of them:

A diamond is a contract that implements the Specification in this standard.
1. **Diamonds can retain addresses through upgrades.** Using a single address for contract functionality makes deployment, testing and integration with other smart contracts, software and user interfaces easier.
Pandapip1 marked this conversation as resolved.
Show resolved Hide resolved
1. **Diamonds can exceed the maximum contract size (Currently 24KB).** You may have related functionality that it makes sense to keep in a single contract, or at a single contract address. A diamond does not have a max contract size.
1. **Diamonds provide a way to organize contract code and data.** You may want to build a contract system with a lot of functionality. A diamond provides a systematic way to isolate different functionality and connect them together and share data between them as needed in a gas-efficient way.
1. **Diamonds provide a way to upgrade functionality.** Upgradeable diamonds can be upgraded to add/replace/remove functionality. Because diamonds have no max contract size, there is no limit to the amount of functionality that can be added to diamonds over time. Diamonds can be upgradeable or immutable. It is also possible to make an upgradeable diamond and then at a later time remove its upgrade capability.

Diamond analogy helps conceptualize development.
## Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

## Motivation
## What is a Diamond?

There are a number of different reasons to use diamonds. Here are some of them:
A diamond is a contract with external functions that are supplied by contracts called **facets**.

1. **A single address for unlimited contract functionality.** Using a single address for contract functionality makes deployment, testing and integration with other smart contracts, software and user interfaces easier.
1. **Your contract exceeds the 24KB maximum contract size.** You may have related functionality that it makes sense to keep in a single contract, or at a single contract address. A diamond does not have a max contract size.
1. **A diamond provides a way to organize contract code and data.** You may want to build a contract system with a lot of functionality. A diamond provides a systematic way to isolate different functionality and connect them together and share data between them as needed in a gas-efficient way.
1. **A diamond provides a way to upgrade functionality.** Upgradeable diamonds can be upgraded to add/replace/remove functionality. Because diamonds have no max contract size, there is no limit to the amount of functionality that can be added to diamonds over time. Diamonds can be upgradeable or immutable. It is also possible to make an upgradeable diamond and then at a later time remove its upgrade capability.
Facets are separate, independent contracts that can share internal functions, libraries and state variables.

### Diamonds Support Transparency

Expand All @@ -55,17 +55,11 @@ The loupe functions can be used for many things including:

Diamonds support another form of transparency which is a historical record of all upgrades on a diamond. This is done with the DiamondCut event which is used to record all functions that are added, replaced or removed on a diamond.

This standard is an improvement of [EIP-1538 Transparent Contract Standard](https://eips.ethereum.org/EIPS/eip-1538). The same motivations of that standard apply to this standard.
This standard is an improvement of [EIP-1538 Transparent Contract Standard](./eip-1538.md). The same motivations of that standard apply to this standard.

See the [Learning & References section](https://eips.ethereum.org/EIPS/eip-2535#learning--references) for additional information and uses of diamonds.
See the [Learning & References section](./eip-2535.md#learning--references) for additional information and uses of diamonds.

## What is a Diamond?

A diamond is a contract with external functions that are supplied by contracts called **facets**.

Facets are separate, independent contracts that can share internal functions, libraries and state variables.

## How a Diamond Works
### How a Diamond Works

A diamond stores within it a mapping of function selector to facet address, for example `selectorToFacet`.

Expand Down Expand Up @@ -104,23 +98,23 @@ An event is emitted any time external functions are added, replaced or removed t

A diamond has four standard external functions that can be called to show what facets and functions it currently has.

## Upgrades and Immutability
### Upgrades and Immutability

A diamond can be immutable from inception by not adding any external functions that can add/replace/remove functions. [There are number of reasons to do this.](#different-kinds-of-diamonds)

A diamond that is mutable can be made immutable by removing such functions.

A diamond can be upgraded if it has a diamondCut external function or other function(s) that can add/replace/remove functions.

## Organizing State Variables in Diamonds
### Organizing State Variables in Diamonds

A state variable or storage layout organizational pattern is needed because Solidity's builtin storage layout system doesn't support proxy contracts or diamonds.

Described below are Diamond Storage and AppStorage which are two state variable organizational patterns that have been successfully used in diamonds.

Another successful pattern has been to write a storage contract that contains all state variables and is inherited by all facets.

## Facets, State Variables and Diamond Storage
### Facets, State Variables and Diamond Storage

A facet defines external functions and can define or use internal functions, libraries, and state variables.

Expand Down Expand Up @@ -172,7 +166,7 @@ By using Diamond Storage facets can declare their own state variables that do no

By using Diamond Storage facets can be developed independently, without connection or concern for other facets.

## AppStorage
### AppStorage

A specialized version of Diamond Storage is AppStorage. This pattern is used to more conveniently and easily share state variables between facets.

Expand Down Expand Up @@ -201,21 +195,21 @@ The above example accesses the `s.firstVar` state variable and stores a computat
Read this article to learn more about AppStorage: [AppStorage Pattern for State Variables in Solidity](https://dev.to/mudgen/appstorage-pattern-for-state-variables-in-solidity-3lki).


## Diamonds Can Use Other Contract Storage Strategies
### Diamonds Can Use Other Contract Storage Strategies

Diamonds and facets don't have to use Diamond Storage or AppStorage. They can use or mix with other contract storage strategies such as contract inheritance.

Diamonds only need to implement the [Specification section](#specification) of this standard.

## Facets Can Share State and Functionality
### Facets Can Share State and Functionality

Facets can share state variables by using the same structs at the same storage positions.

Facets can share internal functions and libraries by inheriting the same contracts or using the same libraries.

In these ways facets are separate, independent units but can share state and functionality.

## Facets are Reusable and Composable
### Facets are Reusable and Composable

A deployed facet can be used by any number of diamonds.

Expand All @@ -227,15 +221,15 @@ The ability to use the same deployed facets for many diamonds reduces deployment

A limitation is that two external functions with the same function signature can't be added to a diamond at the same time because a diamond, or any contract, cannot have two external functions with the same function signature.

## Diagrams
### Diagrams

### Diamond Structure
#### Diamond Structure

This diagram shows the structure of a diamond:

<img src="../assets/eip-2535/DiamondDiagram.png">

### Diamond Storage
#### Diamond Storage

The diagram below shows facets with their own data and data shared between them.

Expand All @@ -251,7 +245,7 @@ In this diagram

<img src="../assets/eip-2535/diamondstorage1.png">

### Deployed Facets Can Be Reused
#### Deployed Facets Can Be Reused

A deployed facet can be used by any number of diamonds.

Expand All @@ -264,7 +258,7 @@ The diagram below shows two diamonds using the same two facets.

<img src="../assets/eip-2535/facetreuse.png">

## Some Diamond Benefits
#### Some Diamond Benefits

1. A stable contract address that provides needed functionality.
1. A single address with the functionality of multiple contracts (facets) that are independent from each other but can share internal functions, libraries and state variables.
Expand All @@ -290,15 +284,15 @@ The diagram below shows two diamonds using the same two facets.
1. Save gas by creating external functions for specific use cases, such as bulk transfers.
1. Diamonds are designed for tooling and user-interface software.

### New User-Interface Software & Libraries
#### New User-Interface Software & Libraries

User-interface software can be written to show all documentation, functions and source code used by a diamond.

Diamond events can be filtered from the Ethereum blockchain to show all changes to a diamond.

Existing and new programming libraries and software can be used to deploy, show, upgrade and use diamonds.

### Upgradeable Diamond vs. Centralized Private Database
#### Upgradeable Diamond vs. Centralized Private Database

Why have an upgradeable diamond instead of a centralized, private, mutable database?

Expand All @@ -309,7 +303,7 @@ Why have an upgradeable diamond instead of a centralized, private, mutable datab
1. Independent security and domain experts can review the change history of contracts and vouch for their history of trustworthiness.
1. It is possible for an upgradeable diamond to become immutable and trustless.

### Different Kinds of Diamonds
#### Different Kinds of Diamonds

Many designs of diamonds are possible. Here are a few kinds of diamonds and their uses.

Expand All @@ -325,27 +319,27 @@ A single cut diamond adds all functions to itself in its constructor function, b
1. Your contract hits the max contract size limit. Make it into a single cut diamond. You still break your big contract into smaller facets, modularizing your code.
2. You start with an upgradeable diamond in your development and testing and upgrade it to your heart's delight. Reap the advantages of easy upgrading and a stable address as you work out new features, bugs and kinks. Release the upgradeable diamond on a test network with your application for beta testing and upgrade it when needed. This is iterative development. When it is solid then deploy it as a single cut diamond on the main network.

## Specification
### Specification

> **Note:**
> The solidity `delegatecall` opcode enables a contract to execute a function from another contract, but it is executed as if the function was from the calling contract. Essentially `delegatecall` enables a contract to "borrow" another contract's function. Functions executed with `delegatecall` affect the contract storage of the calling contract, not the contract where the functions are defined.

> **Note:** This specification specifies what needs to be implemented for a contract to be a diamond.

### Terms
#### Terms

1. A **diamond** is a contract that uses functions from its facets to execute function calls. A diamond can have one or more facets.
2. The word **facet** comes from the diamond industry. It is a side, or flat surface of a diamond. A diamond can have many facets. In this standard a facet is a contract with one or more functions that executes functionality of a diamond.
3. A **loupe** is a magnifying glass that is used to look at diamonds. In this standard a loupe is a facet that provides functions to look at a diamond and its facets.
4. An **immutable function** is a function that is defined directly in a diamond and so cannot be replaced or removed. Or it is a function that is defined in a facet that cannot be replaced or removed because all upgrade functions have been removed from a diamond.

### General Summary
#### General Summary

A diamond calls functions from its facets using `delegatecall`.

In the diamond industry diamonds are created and shaped by being cut, creating facets. In this standard diamonds are cut by adding, replacing or removing facets and their functions.

#### The diamondCut Function
##### The diamondCut Function

The standard `diamondCut` function specified below can be used to add/replace/remove any number of functions from/to a diamond in a single transaction.

Expand All @@ -361,7 +355,7 @@ If you want to create your own custom function(s) for adding/replacing/removing

The `DiamondCut` event records all changes to a diamond.

### Diamond Interface
#### Diamond Interface

```Solidity
interface IDiamondCut {
Expand Down Expand Up @@ -390,7 +384,7 @@ interface IDiamondCut {
}
```

#### Adding/Replacing/Removing Functions
##### Adding/Replacing/Removing Functions

A diamond contains within it a mapping of function selectors to facet addresses. Functions are added/replaced/removed by modifying this mapping.

Expand All @@ -412,21 +406,21 @@ The `diamondCut` function reverts when attempting to replace a function with a f

The `diamondCut` function reverts when attempting to remove a function that already does not exist.

#### Executing \_calldata
##### Executing \_calldata

After adding/replacing/removing functions the `_calldata` argument is executed with `delegatecall` on `_init`. This execution is done to initialize data or setup or remove anything needed or no longer needed after adding, replacing and/or removing functions.

If the `_init` value is `address(0)` then `_calldata` execution is skipped. In this case `_calldata` can contain 0 bytes or custom information.

If the `_init` value is not `address(0)` then `_calldata` must contain more than 0 bytes or the transaction reverts.

#### DiamondCut Event
##### DiamondCut Event

The `_diamondCut`, `_init`, and `_calldata` arguments are passed directly to the `DiamondCut` event.

Any time one or more functions are added, replaced or removed the `DiamondCut` event MUST be emitted to record changes.

### Diamond Loupe
#### Diamond Loupe

> A loupe is a small magnifying glass used to look at diamonds.
> These functions look at diamonds.
Expand Down Expand Up @@ -476,7 +470,7 @@ The loupe functions can be used in deployment functionality, upgrade functionali

Some loupe implementations are not gas efficient and should not be called in on-chain transactions. Some loupe implementations may be gas efficient and can be called in on-chain transactions. Read the documentation of the loupe implementation you use.

### Implementation Points
#### Implementation Points

A diamond implements the following implementation points:

Expand All @@ -490,7 +484,7 @@ A diamond implements the following implementation points:

The diamond address is the address that users interact with. The diamond address does not change. Only facet addresses can change by using the `diamondCut` function, or other function.

## Implementation
## Reference Implementation
Pandapip1 marked this conversation as resolved.
Show resolved Hide resolved

Reference diamond implementations exist in the [Diamond repository](https://github.com/mudgen/Diamond).

Expand Down