March 29, 2018
Blockchain is a promising technology. If used well, it can be a revolutionary technology. It can bring benefits of decentralization, trust and openness while automating things you could not without it. We at Usetech.com have taken these benefits as goals, and were lucky to see an outstanding example of how it can be done – we started learning from Neufund.
NeuFund is a platform for equity fundraising on blockchain. Besides a revolutionary business idea, Nefund does things the way blockchain projects should – by sharing their accomplishment with the community. Their code is open source, and is an excellent example of great programming that we incorporate into our learning program for newcomers. This post is to explain what exactly we find so inspiring. For techies only.
The center of attention are three tokens: Neumark, EtherToken, and EuroToken. Most of remaining source code exists only to be used by these tokens, and of course it is well organized.
Look at this code:
contract Neumark is
This inheritance diagram is impressive even though it does not contain the full list of contracts. As far as OOD, the structure looks very straightforward and organized. Every standard, feature, etc. have their own interface. There is no direct use of Zeppelin framework. You can see Zeppelin package in the code base, but contracts are different from what you see in public Zeppeling github repository. Looks like Zeppelin was not good enough for NeuFund, they decided to tune it up a little and ended up in rebuilding the whole thing from scratch. There are no other traces of any 3rd party code.
NeuFund often talk about this approach in their articles: Build the contract from blocks, and it checks out with what you see very well.
If we step back a little a talk about Solidity development, multiple inheritance is the best thing you can do to use one Solidity class’s functionality in the other class. At first, seems like using aggregation sometimes enables more efficient design patterns in terms of code structure and flexibility. But not in case of Solidity. Remember that we are talking about execution of smart contracts, where every piece of code, every instruction, every byte on stack comes at some cost. Often you can observe that gas efficiency dictates its own patterns. Remember that duck strategy example from Head First Design Patterns book (simplified a bit for sake of saving space):
By the book, optimal pattern is “Mallard is a Duck, and Mallard can Quack.”
In other words, Mallard has Quacking behavior specific to Mallards, which is a more flexible design than inheritance: You can combine, let’s say, any quacking behavior with any flying behavior to make your own type of Duck. But if Mallard was a crypto-duck, you will have to pay extra fee every time you want to hear how it can quack because we would be calling quacking behavior contract from Mallard contract, and that’s more expensive than calling quacking a method. So, we are back to old good inheritance:
“Mallard is a Duck, every Duck can Quack.”
You still pay to hear it quack, but you don’t pay to invoke Quacking behavior contract from Mallard contract because Mallard is a Duck, and Duck naturally knows how to quack (has quacking method).
Of course we lose flexibility given by Strategy design pattern, and you can’t have crypto-rubber-duck quite yet, but there is no better thing today. This only shows that blockchain development is very young and who knows what patterns will evolve in 5 years from now.
You could have seen this article that shows an alternative solution to Zeppelin Ownable contract. The alternative suggests keeping a map of addresses with “isAdmin” flag and have access to some methods that allow admin only access.
NeuFund went event further. Instead of keeping one “isAdmin” flag for the set of “known” addresses, you can set up roles and “subjects” (contracts) which these addresses have privilege to invoke.
People make mistakes. Also people who work in ICOs, including developers of smart contracts, advisers, QA, business analysts, security reviewers, and so on, are not the exception. It is life, and sometimes you just need to scratch everything and start over, but wait… Once the contract is deployed in the blockchain, it stays there forever!
There is no way back, unless you have programmed a capability in the smart contract to be replaced. In case of smart tokens, you need to be fair to your token owners so that contract replacement does not affect their balances. BasicSnapshotToken implements this in an elegant and efficient way. When a token has to be replaced, a new token is given an address of the old token, so the balances are never lost.
They also did not overlook the efficiency: When token owner operates the token contract, first, the address is checked in the most recent token deployment, and only if it is not found there, it is checked in the older contract. We are not in the position to judge if this is fair or not, but at least new token buyers will not pay this extra lookup fee.
NeuFund distributes their NeuMark token to participants based on the exponential curve. We have previously implemented similar algorithm by using piecewise linear interpolation, but NeuFund’s solution comes from a different angle: Instead of interpolation, they are using Taylor series to extrapolate the exponent. While there is no significant gain in single transaction cost, their contracts don’t have to keep the point data for linear interpolation, which is a huge advantage in terms of contract size.
We decided to make our version of the crypto-curves contract and share with the community.
And the last, but not least… If you look at the code, you can’t ignore how much Solidity Assembly is used to optimize gas costs. Some unit tests were created specifically to control gas consumption, for example for CurveGas contract. Both ideas are awesome idea when transaction costs are critical, which we often see in business requirements of our clients.
Years of Solidity experiments and tight quality requirements produced many good things. Thanks for Open Source paradigm and MIT license, under which NeuFund contracts are published, we just learned a lot from their experience.