Here is a scheme for categorizing Ethereum compatibility for some given blockchain. The key is to assess the layers of Program Equivalence:
- Level 0: Full compatibility (Essentially a chain code fork)
- Level 1: Bytecode level compatibility
- Level 2: Code compile-level language compatibility (Eg. Solang)
- Level 3: RPC/endpoint extrinsic compatibility (Eg. Ability to sign using Metamask / Ability to read data using the same block explorers)
While Frontier
’s pallet-evm
and pallet-ethereum
already provide Level 0 compatibility to Substrate, there’s instances where we might prefer native Substrate execution over Frontier’s SputnikVM Runner, as a workaround to its inherent performance penalties. So we want to be able to navigate this scheme as a spectrum of compatibility with legacy EVM standards.
The easiest place to start is at Level 3. From there, climbing up the compatibility levels implies that things can go in a couple different directions, namely:
- EVMless Execution: Re-routing Eth RPCs for native Subtrate execution under multiple FRAME pallets.
-
Wasm Contract Execution: Re-routing Eth RPCs for execution under
pallet-contracts
.
I recently learned about a community effort that is apparently being called WrappedEVM
, including teams like Interlay, Centrifuge and HydraDX. So I’m starting this thread as a way to coordinate those efforts.
EVMless Execution (pallet-evmless
)
The dispatch
precompile is made available by pallet-evm
. It an obvious initial step in this direction, as it opens up the possibility of triggering FRAME execution via Eth RPCs. It is already available and a really low-hanging-fruit for teams aiming to go down this route.
It is still a bit cumbersome, however, because the RPC side is still partially “contaminated” with Substrate, as it requires the actual FRAME calls to be SCALE encoded.
For some cases, we might want the Eth RPCs to believe they’re interacting entirely with an EVM ABI, while staying completely agnostic in regards to the Substrate realm. This starts from the assumption that there are already pallets deployed into the Runtime that are able to cover for all the expected functionality that the ABIs expose.
This would require some mechanism for the Runtime to receive the EVM dispatchables and re-route them for native Substrate execution. This can be achieved with a stripped down version of pallet-evm
(let’s call it pallet-evmless
), that provides a simplified EVM shell Runner. Then, for each Solidity
use-case, different precompiles would be written ad-hoc, either tighly or loosely coupling with the pallets responsible for execution. Unique’s evm-coder
crate can be leveraged here so that developers can focus on writing their precompile logic in Rust without worrying too much about the low-level ABI details.
Ideally, we should standardize pallet-evmless
as a new upstream feature on Frontier
.
Note: I’m using the term EVMless
to describe this specific path of action, while WrappedEVM
is being used as the umbrella term for the overall initiative (which also includes the pallet-contracts
path described below).
Wasm Contract Execution (pallet-contracts
)
While still a WIP, there’s a few tools in our community that have great potential to onboard Solidity
devs into Substrate:
evm-coder
Maintained by Unique Network, evm-coder
is a Rust library for seamless call translation between Rust and Solidity code. Not only it can be quite helpful writing precompiles based on Solidity
contracts (on the EVMless
context described above), but it can also be used while writing ink!
contracts as well.
Sol2Ink
Sol2ink
is able to parse compilable Solidity
interfaces into ink! traits and compilable Solidity
contracts into ink! contracts, while leveraging the power of OpenBrush. The effort is led by SuperColony, but the repository seems stale for the past few months at the time of writing.
Solang
Maintained by the HyperLedger Foundation, Solang
is a Solidity
compiler for Solana (which we don’t really care about here) and Substrate. It is able to compile Solidity
contracts for execution under pallet-contracts
. The project is under active development, with frequent contributions from Parity’s Core Engineering.
pallet-contracts
Be it some Solidity
contract:
- transpiled to
ink!
and then compiled intoWasm
viaSol2ink
orevm-coder
- compiled straight into
Wasm
viaSolang
While deploying them into pallet-contracts
, we might want to still interact with them via Eth RPCs. This would imply new features being added into pallet-contracts
. While theoretically feasible, there might be a few challenges to be tackled along the way:
-
ABI compatibility: currently,
ink!
andSolang
are not following the EVM ABI calling conventions. Making this happen (if even possible) would imply changing theink!
andSolang
calling conventions, which opens a pandora box of breaking changes between different versions and can be seen as tabu. There’s also the problem that theWasm
contracts use types as arguments and return values that don’t exist in the EVM ABI. In this case we would probably just specify them as as bytes and live with the fact that a Dapp needs custom code to encode/decode them. Bottom line is: this topic needs more research.
Edit: as added by @lach in comment below , evm-coder
can potentially help solve some of these issues of ABI compatibility for ink!
.
- EVM tooling compatibility: Tooling might inspect the code. It might be as little as checking for some magic byte and as sophisticated as generating constructor code. It doesn’t matter if it is just a trivial check. That tool will not work as we will be feeding it wasm code. We would need to try to upstream compatibility fixes for the tooling projects.
-
Contract creation: A contract running on
pallet-contracts
contains a dedicated “construction” entry point. When creating a new contract, input data to is passed to this constructor as data in the transaction. This is different from EVM, where the code passed as data is the constructor itself. There are certainly some ways so work around this but it will requireSolidity
developers to do things slightly different from what they are used to.
So there will likely be no perfect on-size-fits-all solution, and we will have to deal with fragmentation at some point. Which is arguably unavoidable, as we can already see in some Eth L2s breaking EVM bytecode and RPC compatibility (e.g.: zkSync and ERC1167).
Nevertheless, this is still a path worth pursuing, as onboarding Ethereum dApps and devs will be really important for the vision of Hybrid Chains in our Ecosystem.