Today we’re releasing four new tools to help Ethereum developers working on smart contracts. We’re excited to finally release these tools publicly, as we have been using them for a while internally at 0x and have shared them with a few other projects in the community.
At 0x, we embrace the UNIX tools philosophy: “each tool should only do one thing, and one thing well.” When we started building 0x protocol, Truffle was the de-facto framework for projects. It worked reasonably well and we’re glad that it helped us get started. However, as we grew, our requirements evolved and we kept pushing the boundaries of what was possible with the framework. Truffle is the Ruby-on-rails of Solidity development and we found it hard to extend it in unintended ways. That’s why we decided to build a set of modular tools that can be combined together and used by others. None of the tools we are releasing today are 0x-specific. You can start using them in your project independently of your current stack (even with Truffle projects!).
By evaluating the existing toolset and breaking up our workflow into logical pieces, we’ve realized that Ethereum development consists of two main stages. Compiling contracts into artifacts and then doing stuff with those artifacts (e.g running tests, debugging, verifying or analyzing metrics, etc…). Unfortunately, there is no single artifact format used by all tools. Some that have reasonable adoption are Truffle’s artifacts and Solidity’s standard JSON output (SSJO from now on). Truffle artifacts include a lot of compiler metadata that we never used and were missing other pertinent pieces of data. Unfortunately, there is no way to customize what compiler metadata is included by Truffle. At the same time, the SSJO format is configurable and can contain only the parts you want.
Want just the ABI? you got it! Need source maps, bytecode, and AST for your fancy debugger? We got you. And it’s what the compiler already outputs — so why reinvent the wheel? The only problem is that SSJO is based around compilation units. One compilation unit could contain multiple smart contracts. We found it more convenient to work with artifacts that correspond 1–1 with a single contract (and it’s dependencies). So, the artifact format we use is heavily inspired by SSJO and contains SSJO sections, but only the sections related to a specific smart contract. Additionally, it also includes some additional information such as deploys by the network.
The good news is that you don’t need to adopt our artifact format in order to use three of our tools! Check out this Truffle example project that uses 3 of the tools.
Sol-compiler is a wrapper around the Solidity compiler that makes it easier to compile entire projects. It produces the artifacts that can be used by all the other tools with zero configuration. Learn more here. I’ll just tease you with the fact that it’s the only solidity compiler I’m aware of that has “watch mode”.
I’m sure some of you will be familiar with this error message:
Error: VM Exception while processing transaction: revert. Instead of that error, you can now get nice stack-trace like in all other modern languages.
If it’s not tested, it’s broken. And how do you know if you’ve tested it? By measuring code coverage with sol-coverage.
Gas is money. Both your money and your user’s money. So why not spend it efficiently and be aware of the bottlenecks and optimization opportunities? Sol-profiler lets you do just that.
The last three tools need to have some information about your smart contracts to work. They can either retrieve this information from truffle artifacts, @0x/sol-compiler artifacts, or from any other source with the help of a small and customizable adapter. Check out any of the docs for more info.
Some of you might be interested to know how these tools work, especially the revert traces since all of these tools are trace-based. Each tool is written as a subprovider that you inject into your provider stack. It then eavesdrops on all your transaction calls and gas estimate requests. When a transaction executes, it fetches it’s trace and uses the source maps to map the data back to lines of Solidity source code or assembly. The traces also contain gas information which is used by the profiler. If you simply ignore the gas information, you end up with code coverage (i.e which lines of the source were executed?).
We have abstracted away most of the technical complexity so that developers can easily use these tools without knowing how they work under-the-hood. Contributions are always welcome and we hope you find these tools useful!