ethermint-simple-smart-contract
is an exercise to deploy a simple smart
contract on an Ethermint blockchain.
It includes running an ethermint node, deploying a local ERC20 token smart contract and writing a client-side program to query and transfer token balances on the deployed smart contract.
For more information on ethermint, please refer to the ethermint documentation
The project's architecture consists of a client and an Ethermintd node. The Ethermintd node represents the EVM blockchain which the client can interact with. The client deploys/migrates contracts on the blockchain in order for them to be available to users of the Ethermint network. Once a contract is deployed to the network, the client allows you to interact with that contract.
You can use frameworks like Truffle or Hardhat to 1) define smart contracts, 2) connect to the node network using the network config, 3) deploy contracts, 4) run tests and 5) interact with the deployed contract. I considered the following implementation options:
- Truffle: Deploy contract with
truffle migrate --network development
or use ethers.js/web3.js to deploy and interact with contract - Hardhat: Deploy and interact with contracts
- Geth: Interact with deployed contract using the geth console
I decided to use truffle for this project because of it's ease of use and extensive documentation.
-
Setup and start a local
Ethermintd node
following the instructions in the Ethermint docs. Before starting the node, set the client config to run a local testnet:{ "chain-id": "ethermint_9000-1", "keyring-backend": "test", "output": "text", "node": "tcp://localhost:26657", "broadcast-mode": "sync" }
-
Git clone this repository into your desired location to get the client:
$ git clone https://github.com/danburck/ethermint-simple-smart-contract $ cd ethermint-simple-smart-contract
-
Install the project npm packages:
$ npm install
-
Configure the
truffle-config
in the project root to connect to your ethereum development client/node (EVM RPC HTTP server)networks: { // Useful for testing. The `development` name is special - truffle uses it by default // if it's defined here and no other network is specified at the command line. // You should run a client (like ganache-cli, geth or parity) in a separate terminal // tab if you use this network and you must also set the `host`, `port` and `network_id` // options below to some value. // development: { host: "127.0.0.1", // Localhost (default: none) port: 8545, // Standard Ethereum port (default: none) network_id: "*", // Any network (default: none) },
The project comes with an ERC20 Token smart contract already implemented. If you like to add your own smart contracts, you can define new smart ontracts at /contracts
and tests at /test
.
-
Compile all contracts:
$ truffle compile
-
Deploy the contract to the node network that you defined in your
truffle-config
:$ truffle migrate --network development
Truffle tests are based on Mocha and Chai. To compile and run the all unit tests for the implemented contract, run:
$ truffle test test/basic_token_test.js --network development
Run the erc20.js
script to deploy the ERC20 token smart contract and invoke balance queries and token transfers:
$ node scripts/erc20.js
You will see a log of query results and transfer receipts, including information such as contract
, address
, gasUsed
, totalSupply
, balances
and more.
To add new contracts follow the following steps:
# Add a new contract
$ touch contracts/MyContract.sol
# Write a new Contract
# Compile your contract.
$ truffle compile
# Create unit tests
$ touch test/my_contract.js
# Run tests
# Migrate your contract
$ truffle migrate
# Write a script to interact with your contract
$ touch scripts/my_contract.js
The smart contract's allowance
-related and massTransfer
functions of the implemented ERC20 token smart contract are not unit tested, as this project focuses on querying a balance and making a simple transfer of tokens.
Further development of this project could include:
- programatic deployment of a smart contract with go
- unit tests for the script
- creating fixtures
-
The Ethermintd node setup on macOS Catalina 10.15.7 throws deprication errors errors at
$ make install
but seems to work fine otherwise. -
Adding a genesis account following the Ethermintd documentation throws errors. The documentation could be more clear by removing the code:
ethermintd add-genesis-account my_validator 10000000000aphoton --keyring-backend test
and only including
ethermintd add-genesis-account my_validator 1000000000stake,10000000000aphoton --keyring-backend=test
Also it would be more clear to add the gentx command:
ethermintd gentx my_validator 1000000stake --keyring-backend=test --chain-id=$CHAINID
and movig the a hint to configure the node from the initialize section to run testnet
-
ethermintd tx bank send
command should include fees:ethermintd tx bank send $MY_KEY $RECIPIENT 20000aphoton --chain-id=$CHAINID --keyring-backend=test --fees='1aphoton'
-
Connecting hardhat to the local node throws
Only HTTP(S) protocals are supported
errors. I used the followinghardhat.config
:module.exports = { networks: { hardhat: { }, development: { url: "localhost:8545", chainID: "ethermint_9000-1", }, }, solidity: "0.8.4", };
Try any hardhat command with, e.g.
npx hardhat accounts --network development
to throw the following error:
An unexpected error occurred: TypeError: Only HTTP(S) protocols are supported at getNodeRequestOptions (/Users/danielburckhardt/code/hardhat-test/node_modules/node-fetch/lib/index.js:1309:9) at /Users/danielburckhardt/code/hardhat-test/node_modules/node-fetch/lib/index.js:1410:19 at new Promise (<anonymous>) at fetch (/Users/danielburckhardt/code/hardhat-test/node_modules/node-fetch/lib/index.js:1407:9) at HttpProvider._fetchJsonRpcResponse (/Users/danielburckhardt/code/hardhat-test/node_modules/hardhat/src/internal/core/providers/http.ts:140:30) at HttpProvider.request (/Users/danielburckhardt/code/hardhat-test/node_modules/hardhat/src/internal/core/providers/http.ts:55:29) at GanacheGasMultiplierProvider._isGanache (/Users/danielburckhardt/code/hardhat-test/node_modules/hardhat/src/internal/core/providers/gas-providers.ts:302:30) at GanacheGasMultiplierProvider.request (/Users/danielburckhardt/code/hardhat-test/node_modules/hardhat/src/internal/core/providers/gas-providers.ts:291:23) at EthersProviderWrapper.send (/Users/danielburckhardt/code/hardhat-test/node_modules/@nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20) at Object.getSigners (/Users/danielburckhardt/code/hardhat-test/node_modules/@nomiclabs/hardhat-ethers/src/internal/helpers.ts:23:20)