Cover photo

Introducing Ethereum Package Manager (EPM)

User avatar

Ken Goldfarb (kencodes.eth)

The future of smart contract development is composability.

TL;DR https://epm.wtf

Last year I was experimenting with keeping NFT metadata entirely on-chain when I hit the 24kb EVM smart contract size limit. This limitation led me to try various workarounds like deploying libraries and additional contracts that call each other. It was messy to maintain and a nightmare to iterate on the contract code.

Searching for a better way, I stumbled on the (EIP-2535) Diamond Proxy Pattern, created by Nick Mudge, which changed everything. Upgradability, infinite contract size, shared contracts. My mind was blown. ๐Ÿคฏ

Since then, I've used the Diamond Pattern in all my smart contracts. Along the way I've developed a bunch of command line scripts to swap out functions ("diamond cuts") and automate some of the more tedious parts of iterating on and testing contracts. But it still felt clunky. And that's why I developed EPM.

The Vision ๐Ÿ‘€

With a few clicks on a webpage, combine smart contracts created by other people (or myself) into my own contract. Maximize re-usability, minimize attack surface, and DRY.

Features ๐Ÿ’ก

With EPM you can deploy a Diamond Proxy, attach facets to it, and then get even more granular by toggling functions on or off!

See it for yourself: https://epm.wtf/manage?address=0xcf169E3D03e46df50f609Ac3b49B66f453E5b6fc&chainId=137

Note: You wonโ€™t be able to edit anything since you donโ€™t own the contract.

Generate Code

Another area of development I found tedious was generating Typescript types for my contracts. With EPM you can download the combined types or ABI (all facet ABIs concatenated) with a click. Just for good measure, there's also a code example of integrating into a React app.

Bundles

Combine facets, toggle functions, and save that configuration for easy deployment by you or someone else!

https://epm.wtf/bundles

Other Uses

EPM supports uploading and deployment of any smart contract. That means you can also use it for non-diamond contracts.

Use Cases

Inheritance By Overriding Functions

I've been experimenting with a sort of inheritance between contracts by having a base contract that implements a function, say handleSaleDistribution(...), and a second contract that implements the same function. I turn the function off in the base contract and on in the second contract. Then, from the base contract I can still call the method.

These don't have to both be contracts written by you. It could be that BaseFacet was uploaded to EPM by someone else. You just need to create OverrideFacet with a single function.

The catch with using this pattern is that it requires you to call the function a little differently in the base contract:

BaseFacet.sol

contract BaseFacet {
	function handleSaleDistribution(address msgSender) public payable {
		if (msg.value == 0) {
			return;
		}

		// By default, send the funds back to the sender
		// Important: Do not use msg.sender here which will be this contract instead of the user initiating the transaction
		payable(msgSender).transfer(msg.value);
	}

	function mint() public payable {
		// ... minting logic

		// IMPORTANT: Call the method using this pattern instead of directly
		BaseContract contract = BaseContract(address(this));
		contract.handleSaleDistribution{value: msg.value}(msg.sender);
	}
}

OverrideFacet.sol

contract OverrideFacet {
	function handleSaleDistribution(address msgSender) public payable {
		if (msg.value == 0) {
			return;
		}

		// Send all funds to Gitcoin
		payable(0xde21F729137C5Af1b01d73aF1dC21eFfa2B8a0d6).transfer(msg.value);
	}
}

Contract Administration

A simpler use case would be keeping an NFT mint off until a contract admin manually flips the switch on by enabling the corresponding function on the Diamond.

Shared Business Logic

It may already be obvious, but it's worth reiterating that Diamond Facets can be shared by multiple Diamond Proxies! This reduces the amount of duplicate code that needs to be deployed and by extension lowers deployment costs.

Nick Mudge just wrote about this

Related Projects

I'm part of Meem, a group of amazing people working to define the relationships between assets and humans with smart contracts. One of our other projects is Clubs which provides tools for online communities.

Behind the scenes, Clubs is using EPM and the Meem API to manage contracts and upgrades. That means you can start with a Clubs contract and customize it with EPM to suit your needs. For more info read how to Customize your Clubs Contract with EPM.

EPM Documentation ๐Ÿ“š

The most up to date information about EPM, Meem, and Clubs.

EPM Documentation

API Endpoints

Considerations ๐Ÿค”

  • Careless upgrades that use Diamond Storage can cause data corruption in the data stored in the contract (๐Ÿคฆโ€โ™‚๏ธ speaking from experience here). It's important to understand exactly how storage works and follow best practices to prevent issues.

Next Steps ๐Ÿš€

Itโ€™s still early and there's a bunch of improvements that can be made to EPM. Just a few that come to mind are...

  • Design / UX updates (in progress)

  • Support more constructor data types when deploying contracts

  • Verified contracts / creators

    • Show audits

    • Links to source code

  • Better "my contracts" contract management / searching

  • Facet compatibility info / warnings

    • Ensure upgrades do not destroy data

  • Decentralized data source

    • Currently Meem maintains the database for EPM but ideally it would live in a decentralized database or shared data storage like IPFS

Have an idea? Want to help develop EPM? Let's chat!

Links

EIP-2535 Further Reading

EIP-2535 Resources

Get in touch

Twitter: @kengoldfarb

Email: hello@kengoldfarb.com

Github: kengoldfarb

Farcaster: @kencodes

  • Loading comments...