during this tutorial we will deploy a smart contract to the blockchain.
for the sake of this tutorial we will use a dockerized test instance based on ganache. follow the description in ganache-docker repository
to spin up a ganache container using the following command.
docker run -p 7545:8545 -d --name ganache ganache
the node version manager is used as the starting point of the dockerized setup based on the suggestion in "mastering ethereum" in appendix dev tools about truffle
the dockerized truffle in this repository is based on updated version of the some github repositories
to create the truffle docker image run the following command.
docker build -t truffle .
docker run -it --rm -v $PWD:/app truffle bash
you now have access to the command line inside the container.
check that truffle is installed successfully via truffle version
.
root@cc3de96a171d:/app# truffle version
Truffle v5.4.11 (core: 5.4.11)
Solidity v0.5.16 (solc-js)
Node v14.17.6
Web3.js v1.5.2
please note that the exact version numbers may change (increase) over time.
still inside the container use the following commands to create the project folder (assuming you are located in this repositorys root directory, otherwise you need to create directory faucet
first).
root@cc3de96a171d:/app#
cd faucet
the following steps are different if you want to create your own project or if you are located in the existing github project.
- exploring this github repository
- setting up your own faucet project
in case you are exploring this github project you skip the steps about truffle init
, npm init
adding the solidty faucet contract file and the javascript migration/deployment file.
in case you'd like to setup your own project you can now use truffle for scaffolding of the faucet project
truffle init
now check the created directory structure using the tree
utility
root@cc3de96a171d:/app/faucet#
tree
.
├── contracts
│ └── Migrations.sol
├── migrations
│ └── 1_initial_migration.js
├── test
└── truffle-config.js
then, let npm
do its work
npm init
accept all suggestions to create a default package.json
file.
in folder contracts add file Faucet.sol
in folder migrations the file 2_deploy_contracts.js
.
this file tells truffle how the contract should be deployed to the blockchain.
in the case of the faucet contract there is hardly anything to do and the script looks a bit like overkill. but then, truffle was created with more complex setups in mind.
with the completed project setup we can now use truffle to complile our smart contract.
for its work, truffle relies on its configuration file truffle-config.js
.
as we had initially started a dockerized local ganache chain we need to provide the coordinates of this chain to truffle in order to deploy the contract to that chain.
to keep the truffle configuration somewhat generic the example file in this github repository uses environment variables to obtain the necessary information.
cat > .env <<EOL
SOLC_VERSION="0.8.0"
HTTP_PROVIDER="http://host.docker.internal:7545"
TRUFFLE_HOST=host.docker.internal
TRUFFLE_PORT=7545
TRUFFLE_NETWORK_ID=*
MNEMONIC="candy maple cake sugar pudding cream honey rich smooth crumble sweet treat"
EOL
in case your docker installation does not support host.docker.internal
you will need to work with the explicit IP address of your machine.
tools like ifconfig
help to figure out this address.
to use the .env
file for the truffle configuration we need to install the dotenv library.
npm install dotenv
we are now ready to compile our contract using truffle as shown below.
truffle compile
to deploy the contract to our dockerized ganache chain we can now simply use
truffle migrate
please note that the information that truffle needs to deploy (blockchain to deploy to, the necessary private key to sign transactions ...) is provided by truffle-config.js
that in turn relies on .env
a successful deploy will provide useful information such as the contracts address, similar to the sample output provided below.
2_deploy_contracts.js
=====================
Deploying 'Faucet'
------------------
> transaction hash: 0x2332e50d737751b41138f27ac6b35c80cf2eccd457685bb97f8c756a277668bc
> Blocks: 0 Seconds: 0
> contract address: 0x345cA3e014Aaf5dcA488057592ee47305D9B3e10
> block number: 3
> block timestamp: 1632403979
> account: 0x627306090abaB3A6e1400e9345bC60c78a8BEf57
> balance: 9999.99177132
> gas used: 124621 (0x1e6cd)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00249242 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00249242 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.00737842 ETH```
successful deployment will also update the meta data files in directory build
maintained by truffle to keep track of what contracts have been deployed on which networks/chains.
for the faucet contract this information will be stored in file build/contracts/Faucet.json
relative to the faucet project directory.
before the deployed contract send any ethers to any requesting address the contract itself needs to actually have its own funds.
for this, move some ethers from the ganache address 0: 0x627306090abaB3A6e1400e9345bC60c78a8BEf57
to the faucet contract
as described in the readme of ganache-docker repository
you may use metamask to transfer funds to the contract address (using the command line output of truffle migrate
or the information in Faucet.json
under attribute networks.<network-id>.address
)
the deployed and funded contract can now be used to distribute "money".
call the withdraw method using the python script that calls the contract on behalf of address 1: 0xf17f52151EbEF6C7334FAD080c5704D77216b732
of our ganache setup.
in the example below the client creates a contract call transaction to transfer 0.123 ethers. for this the client creates a transaction with all the necessary information that is signed using the private key of address 1.
python3 client.py \
-a 0xf17f52151EbEF6C7334FAD080c5704D77216b732 \
-k 0xae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f \
0.123
please note that
- the balance of address 1 will increase slightly less than by 0.123 ethers. the reason for this are the transaction cost of the contract call that is also paid by address 1.
- the contract call will fail if you try to get more than 1 eth
if successful the output should look similar to the one provided below
address 0x627306090abaB3A6e1400e9345bC60c78a8BEf57
pkey 0xc87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3
web3 provider http://host.docker.internal:7545 chain id 1234 connected True
amount in wei 10000000000000000
balance before 9990.161201740000000492 eth account 0x627306090abaB3A6e1400e9345bC60c78a8BEf57
contract object created: Faucet
contract address: 0x345cA3e014Aaf5dcA488057592ee47305D9B3e10
txn created {'value': 0, 'chainId': 1234, 'gas': 2000000, 'gasPrice': 20000000000, 'nonce': 35, 'to': '0x345cA3e014Aaf5dcA488057592ee47305D9B3e10', 'data': '0x2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000'}
txn successfully sent. txn hash b'l\x8b6\xc7\x90_(x\x00 |\xb7o\xc7\xc3*N\x92a\x03\xc8\xf8\xab\x8f\xdc8\xbex\xcd\xb3\x15\xdc'
balance after 9990.170622240000000492 eth account 0x627306090abaB3A6e1400e9345bC60c78a8BEf57