How to use TypeScript with EIP-2535: Diamonds
Tags: tutorial, solidity, web3, typescript
Published: 2022-12-04 19:53:34

[Ethereum Diamond Standard](https://eips.ethereum.org/EIPS/eip-2535) is a finalized standard, which provides a method to create modular smart contract systems that can be extended after deployment. In this post, we will look at how it can be used with TypeScript and TypeChain. Let's begin.

## Diamond Standard

I will not go much into the details of diamonds as there are many that explain it in great detail; [Nick Mudge](https://dev.to/mudgen), the author of this standard, has several posts on <dev.to> that explain more details, see for example: [Understanding Diamonds on Ethereum](https://dev.to/mudgen/understanding-diamonds-on-ethereum-1fb).

In very short terms, a diamond consists of the following:

- At the core, you have a **Diamond** contract. This contract implements a fallback function that can `delegate` call functions on other contracts, each defined as a **Facet**.
- **Facet** is like a face of a diamond, and you can think of the Pink Floyd - Dark Side of the Moon album cover to really imagine what is going on here. You make a call, and that call will be routed somewhere else depending on the `calldata`.
- There are many more details on how entirely this logic works, so I can also refer you to this [series of posts by Ferhat Kocan](https://www.quicknode.com/guides/smart-contract-development/the-diamond-standard-eip-2535-explained-part-1).

I would like to focus in particular from an implementational perspective. There are several reference implementations on GitHub such as [this](https://github.com/mudgen/diamond-3-hardhat) with scripts written in JavaScript. This post is about using TypeScript with the diamonds.

---

If you have been developing contracts and have used TypeScript, chances are you might have used TypeChain. TypeChain generates contract bindings automatically, for example as an Hardhat plugin that runs whenever you compile contracts.

Consider the following tiny ERC20 contract that mints all the supply to the owner on deployment:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyERC20 is ERC20 {
  constructor(
    string memory name_,
    string memory symbol_,
    uint256 supply_
  ) ERC20(name_, symbol_) {
    _mint(msg.sender, supply_);
  }
}
```

Here is what deploying that small ERC20 contract looks like:

```typescript
// import the generated contract types
import {ethers} from 'hardhat';
import {MyERC20, MyERC20__factory} from '../types/typechain';

// get the factory
const erc20Factory = await ethers.getContractFactory('MyERC20', owner)

// deploy with type-safe constructor arguments!
const myERC20 = await erc20Factory.deploy(constants.name, constants.symbol, constants.supply); // returns a MyERC20 type
await myERC20.deployed();

// myERC20 now has type-safe function calls!
```

You can also connect to existing contracts, and cast them to be the type of contract you would like to interact:

```typescript
myERC20 = (await ethers.getContractAt('MyERC20', <contract address>)) as MyERC20;
```

In fact, if you have used TypeChain plugin for hardhat, and `ethers` is imported from hardhat, it sometimes overloads functions such as `getContractAt` to return a typed contract with respect to the contract name, which is awesome.

---

Well, what about diamonds and facets? Well, you can actually make type-safe calls to the facets too!

```typescript
// assuming you have diamond with facets ready
const foobarFacet = (await ethers.getContractAt('FoobarFacet', diamondAddress)) as FoobarFacet;
```

As you can see, it is exactly the same way as before; the only difference is that `diamondAddress` is not where `FoobarFacet` was actually deployed at. In this case, we make calls with `calldata` structures with respect to `FoobarFacet`, and make our calls to the Diamond contract. There they go into `fallback`, and with `delegatecall` we actually run code in our `FoobarFacet`.

I have implemented deployment & testing scripts in TypeScript at the following repo: <https://github.com/erhant/diamonds-with-typescript>. The contracts are taken from the author Nick Mudge's reference implementation. You can analyze the tests for more information on how things work out. There examples of adding, removing, and replacing facet functions.

Happy coding :)

_Cover Picture is generated by a prompt I made on [MidJourney](https://midjourney.com/)._