Action | CPU Cost |
---|---|
ERC20 Transfer | 504µs (TX) |
ERC20 Deploy | 764µs (TX) |
EVM Transfer | 325µs (TX) |
EVM New Address | 553µs (TX) |
The code in this repository has not been audited by a professional audit firm. Please use at your own discretion and risk. The author takes no responsibility for any material or inmaterial losses from any form of operation or deployment of the software within this repository.
- Full Javascript SDK for deploying, executing and querying contracts
- 100% Success on Ethereum Transaction Tests
- 100% Success on Ethereum RLP Tests
- REVERT support (challenging on EOS as it requires no use of eosio::check after nonce increment)
- Istanbul support
- Full gas cost calculations (not billed to sender unless flag enabled)
- Web3-similar call support (query view functions with no state modifications)
- All precompiles supported
eosio.evm supports all 9 precompiles
- ec_recover
- sha256
- ripemd160
- identity
- expmod
- bn_add
- bn_mul
- bn_pairing
- blake2b
All constants are found at constants.hpp
- TESTING - adds functionality for executing tests, and resetting the contract; default true, remove in production
- BN_CURVE - adds bnadd, bnmul, and bnpair precompiles; default true
- CHARGE_SENDER_FOR_GAS - toggle charging sender for gas; default false, required for ethereum tests
- PRINT_LOGS - prints logs as part of execution receipt; default false
- OPTRACE - prints the opcode trace for the execution; default false
- PRINT_STATE - prints the state when saved or loaded from tables; default false
- TOKEN_SYMBOL_CODE_RAW - the symbol of the core token on-chain; default "EOS"
- TOKEN_CONTRACT_RAW - the contract of the core token on-chain; default "eosio.token"
- TOKEN_PRECISION - the precision of the core symbol on-chain; default 4
NOTE: [TESTING, CHARGE_SENDER_FOR_GAS] must be enabled, and [OPTRACE, PRINT_LOGS] must be disabled for ethereum/tests testing to pass successfuly.
NOTE: If ec_add, ec_mul and ec_pairing precompiles are required, set BN_CURVE to true (will increase WASM size by 210KB, or ~2MB onchain).
Deployment steps are laid out step-by-step in both the JS and cleos guides:
JS Guide: eos-evm-js guide
Cleos Guide: cleos guide
Basic Guide: Simply deploy the WASM and ABI at eosio.evm/eosio.evm/eosio.evm.wasm and eosio.evm/eosio.evm/eosio.evm.abi
It is important that any node that you deploy the contract to is running EOSVM OC through the --eos-vm-oc-enable
option
sudo apt install make
sudo snap install cmake --classic
sudo apt install build-essential
wget https://github.com/eosio/eos/releases/download/v2.0.4/eosio_2.0.4-1-ubuntu-18.04_amd64.deb
sudo apt install ./eosio_2.0.4-1-ubuntu-18.04_amd64.deb
wget https://github.com/eosio/eosio.cdt/releases/download/v1.7.0/eosio.cdt_1.7.0-1-ubuntu-18.04_amd64.deb
sudo apt install ./eosio.cdt_1.7.0-1-ubuntu-18.04_amd64.deb
For other platforms than Ubuntu 18.04, check eos and eosio.cdt
Note: You must build eos from source if you wish to manually build the unit tests in eosio.evm
git clone https://github.com/jafri/eosio.evm
cd eosio.evm
cmake .
make -j4
If you wish to build tests, use cmake . -DBUILD_TESTS=true
If not set automatically, you may need to manually set BOOST_ROOT to the directory of your boost installation.
tests/eosio.evm_tests.cpp has five types of tests, which can each be turned on or off individually:
const bool base_enabled = false; // Base testing of linking EOS account
const bool erc20_enabled = false; // Test ERC20 contract deployments
const bool erc721_enabled = false; // Test ERC721 contract deployments
const bool transaction_tests_enabled = false; // Test ethereum/tests TransactionTests
const bool state_tests_enabled = true; // Test ethereum/tests GeneralStateTests
In constants.hpp, TESTING must be enabled to seed initial state of accounts and CHARGE_SENDER_FOR_GAS must be enabled if using unmodified ethereum/tests since tests will only match post-state balances if gas is charged.
If using modified tests to account for no gas being charged, simply ensure CHARGE_SENDER_FOR_GAS is set to false (default), and replace the default path jsontests/BlockchainTests/GeneralStateTests
in eosio.evm_tests.cpp with the path to the modified tests.
Running tests:
cd tests
make -j4
./unit_test # Non-verbose
./unit_test -- --verbose # Expanded logging
- eosio.evm: contains all contract code
- src: all sourcefiles
- include/eosio.evm: all headerfiles
- external: external libraries
- eos-evm-js: Full JS SDK for deploying both EVM and Ethereum accounts, contracts, fetching state, etc.
- evm-mock-rpc: Mock Ethereum RPC server to enable interoperability with Metamask, Remix, etc.
- tests: full Ethereum/EOS tests
- jsontests: copy of https://github.com/ethereum/tests
- system_wasms: eosio.system and eosio.token ABIs/WASMS
- eosio.evm_tests.cpp: testing suite
ACTION raw ( const eosio::name& ram_payer,
const std::vector<int8_t>& tx,
const std::optional<eosio::checksum160>& sender);
ram_payer
Name of account paying for RAM coststx
will take a raw Ethereum transaction RLP hex encoded without the '0x' prefixsender
is an optional parameter used when thetx
is not signed
ACTION create ( const eosio::name& account,
const std::string& data);
account
is the EOSIO account creating the new Ethereum accountdata
is an arbitrary string used as a salt to create the new Ethereum account
ACTION withdraw ( const eosio::name& to,
const eosio::asset& quantity);
account
is the EOSIO account associated with an Ethereum account with a balancequantity
is an EOSIO asset like "4.0000 SYS" for the amount to withdraw
[[eosio::on_notify("eosio.token::transfer")]]
void transfer( const eosio::name& from,
const eosio::name& to,
const eosio::asset& quantity,
const std::string& memo );
- Standard transfer function used to deposit balance into associated Ethereum account. If the depositor does not have an EVM account associated, the transaction will fail to execute.
ACTION call( const eosio::name& ram_payer,
const std::vector<int8_t>& tx,
const std::optional<eosio::checksum160>& sender );
- Function to mock execute and view result (no state modifications are persisted), similiar to Web3 call()
struct Account {
uint64_t index;
eosio::checksum160 address;
eosio::name account;
uint64_t nonce;
std::vector<uint8_t> code;
bigint::checksum256 balance;
}
index
- auto-incremented counter for accounts, also used as scope index for AccountStatesaddress
- Ethereum 160 bit addressaccount
- EOSIO account associated with Ethereum accountnonce
- Current nonce of the accountcode
- Contract code for Ethereum account if presentbalance
- 256 bit balance stored as a bigint (shows as big endian when printed). The precision is 10^18 as specified in Ethereum whitepaper. Therefore, 1 EOS is represented as 1000000000000000000, which is de0b6b3a7640000 in big-endian hex.
struct AccountState {
uint64_t index;
eosio::checksum256 key;
bigint::checksum256 value;
}
index
- auto-incremented counter for account states, only used as primary keykey
- big-endian encoded key for storagevalue
- big-endian encoded value for storage
- Account and code tables were merged to match the specification in the Ethereum Yellow Paper
- Account States are scoped by the index of the account. The index of an account never changes, thus this is guaranteed to be unique.
- NUMBER opcode returns tapos_block_num, as that is the only EOSIO block number available to contracts
- The RLP encoding in "create" uses RLP (uint64_t eos_account, uint64_t nonce)
- No patricia merkle tree is used
- The balance value is printed in explorers, etc as a big-endian hex value with a precision of 10^18, as specified in Ethereum yellow paper. Therefore, 1 EOS is represented as 1000000000000000000, which is de0b6b3a7640000 in big-endian hex.
- Eddy Ashton for his work on enclave-ready EVM (eEVM)
- Pawel Bylica for his work on pushing the speed limits of EVMs with evmone
- winsvega for his continous work maintaining Ethereum Tests
Note that this repository is still in a highly iterative state, if you find any bugs, please open an issue or a pull request.