The Lenia on-chain adventure

Morgan
Lenia NFT
Published in
6 min readNov 3, 2021

Welcome to this “behind the scenes” series and very first Lenia blog post! 🔥

In our effort of being transparent, let’s not only share the successes but also all the drawbacks, sweat, and tears that fills this Lenia journey!

No pain, No gain

TL;DR

  • We set a release date a little bit too early and due to the team organization and a few surprises, we were struggling to stay on time.
  • During the rush, we introduced 2 bugs in the deployed smart contract (remember that a smart contract cannot be changed once it is deployed on the blockchain)
  • Taking inspiration from the Diamond architecture (EIP-2535), we found a solution by adding a new smart contract and linking them together.

You can find the 2 smart contracts here:

Back in time

It was Wednesday, September 22 2021. Alex and I had a call with the rest of the team (NFTribe). Everything was smooth so far, we felt confident in picking a date for the launch. We chose Thursday, October 7 2021, and took the time for the team to meet IRL. Traveling tickets were taken, everything was scheduled. Let’s go!

Fast forward two weeks. Alex and I were sleep-deprived, sweating, and writing code like some frenetic monkeys who didn’t know what they were doing. Of course, the launch of the Lenia NFT collection had to be done in pain, what did you expect?

But why though? Well, two weeks before the launch, when we decided on the launch date, we hadn’t done a quite important step: estimating the gas of deploying our work on the Ethereum blockchain.

We finally did it only 10 days before, and this is when we discovered that we had to optimize many things to make the launch financially acceptable.

On top of that, we still had the website to finish, the smart contract to polish, and wanted to review all the Lenia color palettes. One thing after another, we finally reviewed those color palettes just a few days before launch. But then, you had to render all the assets (it takes time), make sure the metadata and the assets were synchronized and shuffled, etc.

So, we ended up rushing through those last minute changes until we were ready. Focus was quite hard to summon at that point, remember that we were also sleep deprived, stressed, and over-excited at the same time. During that work, the clock was ticking and we were already 30 minutes late!

Outside of the automated tests, we did a final manual check and then, we decided to deploy… without seeing that bugs were lurking… in a smart contract… which cannot be updated…

oups

Bugs

Bug 1

To optimize the overall cost of our smart contract, we decided to create a smart contract library with a lot of hardcoded values. This would allow us to pay once for the library and then be able to use it with a minimal amount of data for all the different Lenia. In doing so, we hardcoded the name of the color palettes.

However, we changed some of those color palettes in the last few days, meaning some of them were removed and others were added. And we didn’t reflect the change in the smart contract library, dooming the library to be unusable.

You can see below that the colors do not match the actual colors of the collection.

Hardcoded colormaps

BUT, we had enough room in the smart contract to circumvent the library and find a solution. At least, we thought until we discovered the second bug.

Bug 2

Let me warn you, this one is fairly stupid.

While we were developing the smart contract, we were pondering over the following feature: should we let owners update their Lenia metadata?

At first, it sounded cool but we started to worry about bad actors who could start to point a Lenia to anything by changing its metadata. Consequently, we concluded to limit that feature to the Lenia smart contract owner.

A copy/paste action later, the onlyOwner keyword (a modifier in Solidity lingo) was added to some of the smart contract functions. The goal was to protect the capacity to update those metadata, not to limit access to it.

But this is what we did, this onlyOwner keyword ended up being added to the wrong function, the one which should have been used to retrieve the data. We doomed another chance to solve our problem.

metadata

Hope

Even after all those bad news, we still managed to do one thing well!

Putting Lenia on-chain requires two parts:

  • The first one is to put Lenia data on-chain.
  • The second one is to upload the JavaScript rendering engine on-chain too.

And we didn’t blow up that second part. This means that we had at least one field, which could be set by the owner and read by everyone inside our smart contract. 🎉

How to use that for our salvation?

Taking inspiration from the best: EIP-2535

EIP-2535 called “Diamonds, Multi-Facet Proxy” describes a standard for building modular smart contract systems that can be extended (or updated) in production.

This standard best feature is the following: Diamonds can be upgraded without having to redeploy existing functionality. Parts of a diamond can be added/replaced/removed while leaving other parts alone.

How does that work? The main contract is called a diamond and it contains external functions that are supplied by other independent smart contracts. The only thing you need to store in the diamond is the mapping of functions to the other smart contract.

This means that as long as you put your custom features outside of your main smart contract, you will be able to update them by deploying a new smart contract and updating the mapping of your diamond.

And right here was the key for us. We won’t implement a diamond but we can use the same logic and use our free field to set the address of another smart contract!

Metadata smart contract

Following the diamond logic, we decided to create a new smart contract, and link our NFT contract to this new contract using the empty engine field.

We kept the new smart contract very concise to minimize errors, it only contains needed functions to store the rendering engine (Javascript) and Lenia metadata (JSON).

Just to be crystal clear, this is not following EIP-2535 but it’s perfectly fine for our use case 👍

Why is it so important to be on-chain?

Outside of purity and beauty consideration (Hi fellow nerds and hackers!). The main goal of being on-chain is to ensure that the data won’t disappear anywhere unless the chain itself disappears. Quite improbable for Ethereum now.

I believe this has a lot of value. It satisfies the promise of Ethereum itself: an immutable and timeless safe for your money, app, and data.

Note: Since the data is quite big, it is currently stored as `callData`, meaning it’s in the logs of the blockchain. If you want to know more, come to speak with us in the discord!

So, did we alter anything?

  • In terms of functionality, no. The data is stored as `callData` in the blockchain logs forever.
  • In terms of code beauty, yes. This is not beautiful and my little heart bleeds every time I’m looking at it.

Hope you enjoyed this little “behind the scene” story! Have a nice day and take care!

Cheers

--

--

Morgan
Lenia NFT

ML engineer & Tech lead. (Former co-founder and CTO @Explee, lenia_nft). ML and crypto enthusiast.