*** Since I could not find a way to isolate namespaces, I had to add another layer of nesting for the mappings, so reading/accessing them gets a little awkward.
Here is how a typical client would use it:
The full code repo is on Github.
The caveat of the entire approach is that you add many wrappers. But it’s still more efficient than deploying the same OZ contracts again and again, as we will see in the next section.
This code is proof of concept and has not been fully optimized or tested. It needs more work to be production ready so please don’t use it for serious projects.
I took well-known contracts like CryptoCoven and InvisibleFriends and modified them as if they had used ERC721C
instead of OZ’s ERC721. I then compared deploy cost, and the cost of transactions like mint
, transfer
, and approve
against the baseline. Here are the results:
As you can see, ERC721C
saves you around 8% of deployment cost but it comes with significant drawbacks to the transaction cost.
The increase in transactions cost comes from the overhead of calling another contract. It also comes from the triply-nested mapping lookup overhead. It is usually better to optimize for run-time gas costs rather than deployment gas costs.
But we should take into account the savings of auditing NFT contracts. With ERC721C
, the bulk of the code will have to be audited only once, and all clients will benefit from this single audit.
ERC721C
is also just a plain copy-paste from OZ’s ERC721 (except for making the architecture shared). It does not have any optimizations specific to this shared architecture. In v2 of ERC721C
, I am planning to add some optimizations, might also try using diamonds (although diamonds will likely not be helpful because their efficiency kicks in in more complex architectures when more than 2 contracts are talking to each other). I might also try using delegatecalls. Let me know (in the comments) if you have additional ideas.
As you can see ERC721C
saves around 8% in deployment cost and a few grand on audit costs per NFT project. But this comes at a significant run-time cost to the minters.
This was my attempt at removing the duplicate code from all NFT contracts. True on-chain composability is the holy grail of web3 and I think today we are not fully going in that direction.
I initially thought that the increased runtime costs would be negligible but turns out external contract calls are very expensive. I will keep iterating on this approach. Hopefully, I can get it to 0 additional run-time overhead. Feel free to contribute to the repo or let me know your thoughts (in the comments).