The porject is built on a frontier template โ FRAME-based Substrate node with the Ethereum RPC support, ready for hacking ๐
To build the chain, execute the following commands from the project root:
$ cargo build --release
To execute the chain, run:
$ ./target/release/atleta-node --dev
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:
{
"AccountId": "EthereumAccountId",
"Address": "AccountId",
"Balance": "u128",
"RefCount": "u8",
"LookupSource": "AccountId",
"Account": {
"nonce": "U256",
"balance": "u128"
},
"EthTransaction": "LegacyTransaction",
"DispatchErrorModule": "DispatchErrorModuleU8",
"EthereumSignature": {
"r": "H256",
"s": "H256",
"v": "U8"
},
"ExtrinsicSignature": "EthereumSignature",
"TxPoolResultContent": {
"pending": "HashMap<H160, HashMap<U256, PoolTransaction>>",
"queued": "HashMap<H160, HashMap<U256, PoolTransaction>>"
},
"TxPoolResultInspect": {
"pending": "HashMap<H160, HashMap<U256, Summary>>",
"queued": "HashMap<H160, HashMap<U256, Summary>>"
},
"TxPoolResultStatus": {
"pending": "U256",
"queued": "U256"
},
"Summary": "Bytes",
"PoolTransaction": {
"hash": "H256",
"nonce": "U256",
"blockHash": "Option<H256>",
"blockNumber": "Option<U256>",
"from": "H160",
"to": "Option<H160>",
"value": "U256",
"gasPrice": "U256",
"gas": "U256",
"input": "Bytes"
}
}
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 look something like:
x: eth.getBalance
340,282,366,920,938,463,463,374,607,431,768,211,455
Further reading: EVM accounts
Running VPP in development mode will pre-fund several well-known addresses
that (mostly) contain the letters "th" in their names to remind you that they
are for ethereum-compatible usage. These addresses are derived from Substrate's
canonical mnemonic: bottom drive obey lake curtain smoke basket hold race
lonely fit walk followed by the name of an account (i.e bottom drive obey lake curtain smoke basket hold race lonely fit walk//Alith
)
# Alith (sudo):
- Address: 0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac
- PrivKey: 0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133
# Baltathar:
- Address: 0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0
- PrivKey: 0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b
# Charleth:
- Address: 0x798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc
- PrivKey: 0x0b6e18cafb6ed99687ec547bd28139cafdd2bffe70e6b688025de6b445aa5c5b
# Dorothy:
- Address: 0x773539d4Ac0e786233D90A233654ccEE26a613D9
- PrivKey: 0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68
# Ethan:
- Address: 0xFf64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB
- PrivKey: 0x7dce9bc8babb68fec1409be38c8e1a52650206a7ed90ff956ae8a6d15eeaaef4
# Faith:
- Address: 0xC0F0f4ab324C46e55D02D0033343B4Be8A55532d
- PrivKey: 0xb9d2ea9a615f3165812e8d44de0d24da9bbd164b65c4f0573e1ce2c8dbd9c8df
# Goliath:
- Address: 0x7BF369283338E12C90514468aa3868A551AB2929
- PrivKey: 0x96b8a38e12e1a31dee1eab2fffdf9d9990045f5b37e44d8cc27766ef294acf18
# Heath:
- Address: 0x931f3600a299fd9B24cEfB3BfF79388D19804BeA
- PrivKey: 0x0d6dcaaef49272a5411896be8ad16c01c35d6f8c18873387b71fbc734759b0ab
# Ida:
- Address: 0xC41C5F1123ECCd5ce233578B2e7ebd5693869d73
- PrivKey: 0x4c42532034540267bf568198ccec4cb822a025da542861fcb146a5fab6433ff8
# Judith:
- Address: 0x2898FE7a42Be376C8BC7AF536A940F7Fd5aDd423
- PrivKey: 0x94c49300a58d576011096bcb006aa06f5a91b34b4383891e8029c21dc39fbb8b
Also, the pre-funded default account for testing purposes is:
# Gerald:
- Address: 0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b
- PrivKey: 0x99b3c12287537e38c90a9219d4cb074a89a16e9cdb20bf85728ebd97c343e342
The node should run locally in --dev
mode.
Then you need to configure the network this way:
- chain ID is 2340
- chain name is atleta
- currency name is Atleta Token
- currency symbol is ATLA
- currency decimals is 18
- RPC URL is http://localhost:9944/ (or change appropriately to where you deploy the node)
The project supports ink! smart contracts. For detailed instructions and more information on ink!, please visit the ink! documentation site.
Before starting with ink! contracts, please ensure that you develop them in a separate project/repository.
To begin developing ink! contracts, you must first install the necessary cargo plugin:
$ cargo install cargo-contract --force
To generate an initial smart contract, execute the following command:
$ cargo contract new <contract_name>
To compile smart contract:
$ cargo contract build --release
The following steps are also available as a Typescript script using Polkadot JS SDK.
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).
Use the Chain State
UI tab to query evm > 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
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
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.