a frontier based evm compatible chain template

Overview

Substrate Frontier Node Template

A FRAME-based Substrate node with the Ethereum RPC support, ready for hacking 🚀

Generation & Upstream

This template is maintained in the Frontier project repository, and can be used to generate a stand-alone template for use in an independent project via the included template generation script.

A ready-to-use template generated this way is hosted for each Frontier release on the substrate-developer-hub/frontier-node-template repository.

This template was originally forked from the Substrate Node Template. You can find more information on features on this template there, and more detailed usage on the Substrate Developer Hub Tutorials that use this heavily.

Build & Run

To build the chain, execute the following commands from the project root:

$ cargo build --release

To execute the chain, run:

$ ./target/debug/frontier-template-node --dev

The node also supports to use manual seal (to produce block manually through RPC).
This is also used by the ts-tests:

$ ./target/debug/frontier-template-node --dev --manual-seal

Docker Based Development

Optionally, You can build and run the frontier node within Docker directly.
The Dockerfile is optimized for development speed.
(Running the docker run... command will recompile the binaries but not the dependencies)

Building (takes 5-10 min):

docker build -t frontier-node-dev .

Running (takes 1 min to rebuild binaries):

docker run -t frontier-node-dev

Genesis Configuration

The development chain spec included with this project defines a genesis block that has been pre-configured with an EVM account for Alice. When a development chain is started, Alice's EVM account will be funded with a large amount of Ether. The Polkadot UI can be used to see the details of Alice's EVM account. In order to view an EVM account, use the Developer tab of the Polkadot UI Settings app to define the EVM Account type as below. It is also necessary to define the Address and LookupSource to send transaction, and Transaction and Signature to be able to inspect blocks:

{
	"Address": "MultiAddress",
	"LookupSource": "MultiAddress",
	"Account": {
		"nonce": "U256",
		"balance": "U256"
	},
	"Transaction": {
		"nonce": "U256",
		"action": "String",
		"gas_price": "u64",
		"gas_limit": "u64",
		"value": "U256",
		"input": "Vec<u8>",
		"signature": "Signature"
	},
	"Signature": {
		"v": "u64",
		"r": "H256",
		"s": "H256"
	}
}

Use the Developer app's RPC calls tab to query eth > getBalance(address, number) with Alice's EVM account ID (0xd43593c715fdd31c61141abd04a99fd6822c8558); the value that is returned should be:

x: eth.getBalance
340,282,366,920,938,463,463,374,607,431,768,211,455

Further reading: EVM accounts

Alice's EVM account ID was calculated using an included utility script.

Example 1: ERC20 Contract Deployment using EVM dispatchable

The following steps are also available as a Typescript script using Polkadot JS SDK

Step 1: Contract creation

The truffle directory contains a Truffle project that defines an ERC-20 token. For convenience, this repository also contains the compiled bytecode of this token contract, which can be used to deploy it to the Substrate blockchain.

Further reading: the ERC-20 token standard

Use the Polkadot UI Extrinsics app to deploy the contract from Alice's account (submit the extrinsic as a signed transaction) using evm > create with the following parameters:

source: 0xd43593c715fdd31c61141abd04a99fd6822c8558
init: <raw contract bytecode, a very long hex value>
value: 0
gas_limit: 4294967295
gas_price: 1
nonce: <empty> {None}

The values for gas_limit and gas_price were chosen for convenience and have little inherent or special meaning. Note that None for the nonce will increment the known nonce for the source account, starting from 0x0, you may manually set this but will get an "evm.InvalidNonce" error if not set correctly.

Once the extrinsic is in a block, navigate to the Network -> Explorer tab in the UI, or open up the browser console to see that the EVM pallet has fired a Created event with an address field that provides the address of the newly-created contract:

# console:
... {"phase":{"applyExtrinsic":2},"event":{"index":"0x0901","data":["0x8a50db1e0f9452cfd91be8dc004ceb11cb08832f"]} ...

# UI:
evm.Created
A contract has been created at given [address]
   H160: 0x8a50db1e0f9452cfd91be8dc004ceb11cb08832f

In this case, however, it is trivial to calculate this value: 0x8a50db1e0f9452cfd91be8dc004ceb11cb08832f. That is because EVM contract account IDs are determined solely by the ID and nonce of the contract creator's account and, in this case, both of those values are well-known (0xd43593c715fdd31c61141abd04a99fd6822c8558 and 0x0, respectively).

Step 2: Check Contract Storage

Use the Chain State UI tab to queryevm > accountCodes for both Alice's and the contract's account IDs; notice that Alice's account code is empty and the contract's is equal to the bytecode of the Solidity contract.

The ERC-20 contract that was deployed inherits from the OpenZeppelin ERC-20 implementation and extends its capabilities by adding a constructor that mints a maximum amount of tokens to the contract creator. Use the Chain State app to query evm > accountStorage and view the value associated with Alice's account in the _balances map of the ERC-20 contract; use the ERC-20 contract address (0x8a50db1e0f9452cfd91be8dc004ceb11cb08832f) as the first parameter and the storage slot to read as the second parameter (0x045c0350b9cf0df39c4b40400c965118df2dca5ce0fbcf0de4aafc099aea4a14). The value that is returned should be 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff.

The storage slot was calculated using a provided utility. (Slot 0 and alice address: 0xd43593c715fdd31c61141abd04a99fd6822c8558)

Further reading: EVM layout of state variables in storage

Step 3: Contract Usage

Use the Developer -> Extrinsics tab to invoke the transfer(address, uint256) function on the ERC-20 contract with evm > call and transfer some of the ERC-20 tokens from Alice to Bob.

target: 0x8a50db1e0f9452cfd91be8dc004ceb11cb08832f
source: 0xd43593c715fdd31c61141abd04a99fd6822c8558
input: 0xa9059cbb0000000000000000000000008eaf04151687736326c9fea17e25fc528761369300000000000000000000000000000000000000000000000000000000000000dd
value: 0
gas_limit: 4294967295
gas_price: 1

The value of the input parameter is an EVM ABI-encoded function call that was calculated using the Remix web IDE; it consists of a function selector (0xa9059cbb) and the arguments to be used for the function invocation. In this case, the arguments correspond to Bob's EVM account ID (0x8eaf04151687736326c9fea17e25fc5287613693) and the number of tokens to be transferred (0xdd, or 221 in hex).

Further reading: the EVM ABI specification

Step 4: Check Bob Contract Storage

After the extrinsic has finalized, use the Chain State app to query evm > accountStorage to see the ERC-20 balances for both Alice and Bob.

You might also like...
OOLANG - an esoteric stack-based programming language where all instructions/commands are differnet unicode O characters

OOLANG is an esoteric stack-based programming language where all instructions/commands are differnet unicode O characters

A stack based, virtual machine language written in Rust

Stackyy A stack based, virtual machine language written in Rust Description: Stackyy is a stack based, virtual machine language inspired by Forth and

Tools to feature more lenient Polonius-based borrow-checker patterns in stable Rust
Tools to feature more lenient Polonius-based borrow-checker patterns in stable Rust

Though this be madness, yet there is method in 't. More context Hamlet: For yourself, sir, shall grow old as I am – if, like a crab, you could go back

A simplistic functional programming language based around Lisp syntax.

Orchid A simplistic functional programming language based around Lisp syntax. Short taste # function to return the larger list (fn larger-list (as bs)

lelang programming language is a toy language based on LLVM.

lelang leang是一门使用Rust编写,基于LLVM(inkwell llvm safe binding library)实现的编程语言,起初作为课程实验项目,现在为个人长期维护项目。 Target Features 支持8至64位的整形类型和32/64位浮点 基本的函数定义,调用,声明外部

API for the creation character based games in Linux.
API for the creation character based games in Linux.

Console Game Engine for Linux. API for the creation of character based games in Linux. The inspiration came from the olcConsoleGameEngine. This is my

Stack-based programming language which emulates the look and feel of the 60s

Cauchemar Cauchemar is a stack-based programming language inspired by FORTH but more arcane. Emulates the look and feel of a programming language from

Diosic is an open source web-based music collection server and streamer

Diosic is an open source web-based music collection server and streamer. Mainly suitable for users who need to deploy on servers with low hardware specifications.

Rust crate implementing short & stable ids based on timestamps

Lexicoid Short & stable IDs based on timestamps. Heavily inspired by Short, friendly base32 slugs from timestamps by @brandur. Install Install with ca

Owner
zero network
substrate based multichain and sdk for video games
zero network
Write Anchor-compatible Solana programs in Python

seahorse: Write Solana programs in Python The ease of Python with the safety of Rust. Seahorse lets you write Solana programs in Python. It is a commu

✨ amelia chen ✨ 214 Dec 28, 2022
A SCALE-compatible collection of bits

scale-bits · This small utility crate provides two separate things: A Bits type that can be SCALE encoded and decoded, and is fully SCALE compatible w

Parity Technologies 3 Sep 25, 2022
An asynchronous runtime compatible with WebAssembly and non-WebAssembly targets.

Promise x Tokio = Prokio An asynchronous runtime compatible with WebAssembly and non-WebAssembly targets. Rationale When designing components and libr

Yew Stack 29 Feb 6, 2023
OP-Up is a hive tool for testing OP-Stack-compatible software modules

op-up Warning This is a work in progress. OP-Up is a hive tool for testing OP-Stack-compatible software modules. This project was born out of the need

nicolas 20 Jun 13, 2023
Rust template repository.

Rust template repository. An opinionated starting point for rust projects such as systemd services command line tools client programs server programs

Kris Nóva 42 Dec 28, 2022
An MVP stack based bytecode VM

TinyVM An MVP stack-based bytecode VM This VM runs a simplistic, Turing complete instruction set. In ~250 LOC with extensive comments, it's meant to b

Mikail Khan 77 Dec 27, 2022
An expression based data notation, aimed at transpiling itself to any cascaded data notation.

Lala An expression oriented data notation, aimed at transpiling itself to any cascaded data notation. Lala is separated into three components: Nana, L

null 37 Mar 9, 2022
A stack based interpreted programming language.

Nightmare Nightmare is a dynamically-typed, procedural programming language that aims to be fast & simple. let user = input() as Int; print("You were

&potato 4 Nov 12, 2021
A Rust no-std (de)compressor based on PAQ

MASHI まし A 100% no-std compatible Rust implementation of a PAQ style arithmetic coding, context mixing compressor. Its intended use case is compressin

null 7 Dec 14, 2022
An embedded key-value storage for learning purpose, which is based on the idea of SSTable / LSM-tree.

Nouzdb An embedded key-value storage for learning purpose, which is based on the idea of SSTable / LSM-tree. Plan Implement a memtable. Implement the

Nouzan 1 Dec 5, 2021