Second Steps
In this section we are going to introduce a few powerful tools to make your development experience as easy as possible. We will install a development environment called Truffle, explore Solidity, cover the fundamentals of a smart contract (we鈥檒l even make our own!), and start our very own node on our local machine. Once we have successfully deployed locally, we will use Remix to interact with our contract and dive deeper into the development process!
Getting Familiar With Truffle
Truffle
Truffle is an excellent development environment that allows you to both connect with and test using the Ethereum Virtual Machine. Truffle was created to make development easier, and with interactions occurring locally this helps reduce the stress of deployment on both a testnet (such as Ropsten or Rinkeby) and mainnet.
For more documentation on Truffle take a look here:
To install Truffle in your terminal go ahead and run the following:
npm install truffle -g
Note: Recommendations for Windows
If you鈥檙e running Truffle on Windows, you may encounter some naming conflicts that could prevent Truffle from executing properly. Please see the section on resolving naming conflicts for solutions.
Ganache聽
While we are at it let鈥檚 go ahead and install the CLI for ganache
A quick rundown on ganache is that it鈥檚 a personal blockchain you can use locally to quickly spin up and test functionality of projects. Ganache is a tool you can use throughout the entirety of the development cycle. Not only are you able to develop, but also deploy, and test your dApps. All of this happens locally on your machine so this is the lowest friction / risk environment to work on your projects!
Using npm:
npm install -g ganache-cli
Ok, back to truffle!
Some of the offerings Truffle provides:
- Built-in smart contract compilation, linking, deployment and binary management.
- Automated contract testing for rapid development.
- Scriptable, extensible deployment & migrations framework.
- Network management for deploying to any number of public & private networks.
- Package management with EthPM & NPM, using the ERC190 standard.
- Interactive console for direct contract communication.
- Configurable build pipeline with support for tight integration.
- External script runner that executes scripts within a Truffle environment.
For our tutorial we are going to build something from the ground up, however you are absolutely encouraged to check out some of the boiler projects Truffle has already created called Truffle Boxes (found here).
Now that we have truffle and ganache installed, let鈥檚 discuss solidity!
Solidity聽
Solidity is an incredibility popular object-oriented, high-level language for implementing smart contracts that run on the Ethereum Virtual Machine (EVM). Smart contracts are programs which govern the behavior of accounts within the Ethereum state. If you鈥檝e never looked at a line of Solidity prior, but are familiar with C++ and or JavaScript you will notice more than a few similarities.聽
Solidity is a statically typed language that supports inheritance, libraries, and complex user-defined types among other features. With Solidity you can create contracts for uses such as voting, crowdfunding, even blind auctions to name just a few uses cases.聽
Solidity is compiled into bytecode that is executable on the EVM. With Solidity, developers are able to write applications that implement self-enforcing business logic embodied in smart contracts, leaving for a non鈥repudiation record of transactions. Smart contracts allow users to trust the code, which assists in creating a trustless environment where potential human corruption is greatly removed.聽
Keep in mind when deploying contracts, you should always pay attention to the version you鈥檙e using. Breaking changes, new features, and bug fixes are introduced regularly (remember this if you find yourself following tutorials online, running into errors can happen, so keep the documentation close to you).聽
Starting a Truffle Project聽
With that said let鈥檚 start our project and name it 鈥渆th-hello-world鈥
Jump in your terminal and let鈥檚 create a new empty folder聽
mkdir eth-hello-world
Once we have our empty directory go ahead and jump into the folder and run the command
truffle init
Once the process finishes we should be able to view some the files that were created for us:
We now have contacts, migrations, a test folder, and a truffle-config file. Let鈥檚 have a look into these files and discuss at a higher level聽 what they are.
Contracts
This folder will contain all of your smart contracts (which in this example we will be creating using Solidity). If you鈥檝e never heard of smart contacts, a way to think about them is; pieces of code that run on the blockchain (this can be local, test, or mainnet) that are guaranteed to produce the same results for everyone running them. Smart Contracts are used within dApps (decentralized applications) and have a tremendous amount of use cases. Voting, gaming, supply chain, currencies, financial records, and that鈥檚 just to name a few!
To break this down even further Nick Szabo gives the vending machine example. If you put in the correct amount of coins into the machine, you (and everyone before / after you) can expect the same exact result in exchange. The same goes for smart contacts built on Ethereum, they contain a value and until their conditions are met (i.e. the right amount of coins in our example) it will then unlock and release the information you鈥檙e trying to retrieve.
We will come back to discussing Solidity and smart contracts a little later on, let鈥檚 move on to migrations!
Migrations
Migrations are Javascript files that allow you to deploy your contracts to the Ethereum network. What鈥檚 really interesting about them is there is an underlying assumption your work will evolve, and your deployment will change over time. As you make updates, you鈥檒l make new migration scripts during your project鈥檚 evolution. A way to think about migration files is they are predominantly responsible for the staging and deployment of your tasks. A simple way to think about them is migrations are a set of managed deployment scripts. As you update your work, a log of your previously run migrations is recorded on-chain through a build-in Migrations contract.
Take a look for yourself, you already have a migration contract! Head over to your contract directory and open it up, you鈥檒l see a Migrations.sol file that contains a contract that should look something like this:
This is a default contract that is created for us when we run truffle init. Truffle by nature requires you to have a Migration contract in order to use the migration feature, so don鈥檛 delete this!
Note: You must deploy this contract inside your first migration in order to take advantage of the Migrations feature.
Now that we鈥檝e had a chance to look at our Migration contract we can head over to the migration directory and we will see a file named 1_inital_migrations.js
Note: Take a look at the naming convention of this file, it is prefixed with a number and is suffixed by a description. The numbered prefix is required in order to record whether the migration ran successfully. The suffix is purely for human readability
As you create contracts, you鈥檒l need to make sure you have a migration.js file in conjunction to them. Without diving too deep into artifacts.require(), deployer.deploy, etc here is some excellent documentation from the truffle team to further explain the usage of these methods.
To compile a Truffle project, change to the root of the directory where the project is located and then type the following into a terminal:
truffle compile
To run your migrations in your terminal you鈥檒l eventually run (hold on though, we don鈥檛 need to do this yet!)
truffle migrate
This will run all migrations located within your project鈥檚 migrations directory.
What鈥檚 interesting to note is this command will only run newly created migrations. So if your previous migration ran successfully, it will not rerun it. Also, if no new migrations exist to run, it simply won鈥檛 run. If needed you can use the 鈥搑eset option to run all your migrations from the beginning.
Other command options are documented here.
Note: We installed earlier, but for local testing make sure to have a test blockchain such as Ganache installed and running before executing migrate.
Testing
When it comes to writing tests truffle comes loaded with some excellent tools to make this intuitive. Especially if you plan on deploying your contracts to mainnet, (but it鈥檚 good practice, even on testnet) it鈥檚 very important to run tests and check your contracts to the best of your abilities. Truffle has made it simple and manageable to review / test your development.
Truffle uses the Mocha testing framework and Chai for assertions to provide you with a solid framework from which to write your JavaScript tests.聽
Note: If you鈥檙e unfamiliar with writing unit tests in Mocha, please see Mocha鈥檚 documentation before continuing.
Side note: An excellent tool to utilize to review your contracts thoroughly is Mythx, the premier security analysis service in the field offering in- depth reviews for smart contracts. Their mission is to not only ensure you avoid costly errors but to make Ethereum a more secure and trustworthy platform overall.
All test files should be located in the ./test directory. Truffle will only run test files with the following file extensions: .js, .ts, .es, .es6, .jsx, and .sol. All other files are ignored.
To run all tests, simply run:
truffle test
Now that we have covered what truffle init creates and the scaffolding of our project, let鈥檚 now go ahead and add our smart contract to our project!
Writing a Smart Contract
Let鈥檚 jump into the contract directory and write our first contract we plan on deploying to our local test environment (ganache)!
We will start out by creating our .sol file, which we will name HelloWorld.sol
Next we can add our basic contract which will look something like this
pragma solidity >=0.5.8 <0.7.0;
contract HelloWorld {
string public message;
constructor(string memory initMessage) public {
message = initMessage;
}
function update(string memory newMessage) public {
message = newMessage;
}
}
Looking at our contract a little closer we can break down a few elements
Remember, a contract is a collection of functions and data (its state).
The pragma keyword can be used to enable certain compiler features or checks. A pragma directive is always local to a source file, so you have to add the pragma to all your files if you want enabled in your project. Without a declaration of pragma at the start of our (or any) solidity file, our contract will not know how to compile.
(here is a link to the solidity docs to learn the ins and outs of solidity nuances)
Ultimately, a contract is a collection of functions and data (its state) that resides at a specific address on the Ethereum blockchain.
Looking at the functionality of our contract we can see we are setting our message to be viewable public string.聽
The keyword 鈥減ublic鈥 makes variables accessible from outside a contract and creates a function that other contracts or SDKs can call to access the value string public message.
contract HelloWorld {
string public message;
Here is a function that only runs during the creation of the contract聽
constructor(string memory initMessage) public {
message = initMessage;
}
It takes a string value and stores the value in the memory data storage area, setting message to that value message i.e. initMessage.
We can then initialize a message that is passed as a parameter and can be altered / updated with the update function.
This is publicly accessible function that takes a string as a parameter and updates `message` (see below).
function update(string memory newMessage) public {
message = newMessage;
}
}
There you have it, a basic but digestible HelloWorld contract!
Now that we have our contract added we can now make sure it has the ability to compile!
Head over to the Migration folder in our project and we will now make a .js file dedicated to our HelloWorld contract.
We will create a new file and name is 2_deploy_contracts.js
Remember the note on naming conventions from earlier!
const HelloWorld = artifacts.require("HelloWorld");
module.exports = function (deployer) {
deployer.deploy(HelloWorld, "string");
};
Nice work! We are almost ready to deploy our contract, but first we need to make sure our truffle-config files knows who to talk to. As mentioned earlier we are going to focus on our local environment in this section, but in section 3 (spolier) we not only create and deploy locally, we bring it on to a test network!
Scroll down in your truffle-config.js file until you see the section pertaining to networks
uncomment / add the following聽
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*",
},
Now your file should look something like this:
聽
Whats happening here is we are tell our config file specific directions on what to connect with. In this case as you鈥檒l see soon, we will be connecting to our ganache-cli tool.
Start Ganache
With that said let鈥檚 go ahead and start up our ganache聽
in your terminal go ahead and run聽
ganache-cli
Check it out! You are now running your own TestRPC right there in your terminal!聽
(more on this here)
Note: Keep this tab in your terminal open, but go ahead and open a new one to work out of.
Quick Review聽
Let鈥檚 head back to our project and take a quick to review what we鈥檝e done.聽
- We created a new project
- Initialized Truffle
- Took a quick tour of the scaffolding
- Created our HelloWorld contract
- Added logic to our migrations folder for our contract
- Went into our config file and adjusted our network information聽
Time to get our contract up and running!聽
In our new terminal window (since we have ganache running in the other)聽
let鈥檚 go ahead and run聽
truffle compile
You should now see this as as result in your terminal:
If you now go to your project you鈥檒l see you now have a build / contracts folder above your contract folder containing two .json files. You should see:聽
- HelloWorld.json
- Migrations.json聽
The .json file at a high level describes the deployed contract and its functions. It allows us to contextualize the contract and call its functions.
If we take a look inside we can see a whole bunch of information:
聽
We dive into this information deeper in step three but something important to take a look at is the ABI.
The Application Binary Interface is a data encoding scheme used in Ethereum for working with smart contracts.
Taking a look at the information it鈥檚 relatively intuitive to understand. The ABI also defines how the user can call the functions 鈥 that is, the location of the function in relation to the smart contract address. A high level summarization is the ABI is the description of the contract interface. It does not contain code and doesn鈥檛 have the ability to run by itself. Then you have the bytecode, which is the executable EVM code but by itself it is without context.
Time to migrate
OK!聽
So now that we have our ganache-cli running and we鈥檝e compiled our smart contract so now it鈥檚 time to migrate our contracts!聽
in your terminal go ahead and run聽
truffle migrate
YES! You did it!
We can see we have successfully deployed our smart contract. You can see some really helpful information was generated and if you head to your other tab with ganachi-cli running you should see a TransactionReceipt (take a look for yourself).
Test ETH聽
Before we head over to Remix we need to get a hold of some test ETH so we can pay the gas fees on Remix (don鈥檛 worry this won鈥檛 cost you actually money).聽
Head over to this faucet and grab some Rinkeby. We dive into what test ETH is in step 3, but in this step just know we will be using Rinkeby which is a Proof of Authority network opposed to let鈥檚 say Ropsten which is a Proof of Work testnet (which is more similar to the public main net). After completing steps 2 and 3 you鈥檒l have some of both in your MetaMask wallet to experiment with!
Remix
Ok, now that we have some test EHT it鈥檚 time to head over to Remix and deploy our contract outside of our local environment and even have the ability to interact with it!
鈥渨hat the heck is Remix?鈥澛
Glad you asked!聽
Remix is a powerful, open source tool that helps you write Solidity contracts straight from the browser. One really amazing element in particular about Remix is that it supports both usage in the browser and locally! Remix supports testing, debugging, and contract deployment to name a few key features. Remix should be considered a staple tool for a developer in their building process. Starting with local deployment (as we did earlier) with ganache is an excellent foundation, moving from local deployment we can experiment and interact with our contract on Remix.
Taking proper persuasions and testing (again and again) your development before a potential launch to the main ethereum network can save you perhaps more than a headache!
Now let鈥檚 take the same contract and deploy it outside of our local environment using Remix聽
Link here聽
Our contract聽
Click on new file and let鈥檚 name it HelloWorld.sol
(here is the contract we will be using again)聽
pragma solidity >=0.5.8 <0.7.0;
contract HelloWorld {
string public message;
constructor(string memory initMessage) public {
message = initMessage;
}
function update(string memory newMessage) public {
message = newMessage;
}
}
We can now go ahead and add our contract in the field. (Check it out below)聽
Now let鈥檚 check out the left menu that asks for your selected compiler version.
Compiler
Keep in mind within our contract we have declared our compiler range.
Remember the pragma keyword is used to enable certain compiler features or checks.聽
So we can set our compiler to 0.6.0 which falls between our provided range (see blow)聽
Our contract should automatically compile, if not go ahead and click Compile HelloWorld.sol
Next we will set up our Environment to deploy our contract!聽
Deploy and run transactions
Environment聽
You鈥檒l notice a few different options when selecting your environment:
JavaScript聽VM: All the transactions will be executed in a sandbox blockchain in the browser. This means nothing will be persisted when you reload the page. The JsVM is its own blockchain and on each reload it will start a new blockchain, the old one will not be saved.
Injected聽Provider: Remix will connect to an injected web3 provider.聽Metamask聽is an example of a provider that inject web3.
Web3聽Provider: Remix will connect to a remote node. You will need to provide the URL to the selected provider: geth, parity or any Ethereum client.
In this example we are going to use: Injected Web3
We will use our MetaMask wallet and make sure we are connected to our Rinkeby test Network聽
We can see on the left side we are connected to Rinkeby and also see our connected account address!聽
Once we have everything set, let鈥檚 go ahead and deploy our contract!
馃帀We did it! 馃帀聽
Check out the provided terminal and you can see the confirmation
Now we have the ability to view our deployed contract, we can update our message (we have to both sign and pay the gas fee for this since we are updating the state)
Once we have confirmation we can see our message has updated!
馃コ Well done!聽馃コ聽
We鈥檝e taken the contract that we initially started with locally and have deployed that contract on Remix to have a visual representation of contract interaction. This is a healthy flow for developer as they start to build in this space. Remix is an incredible tool that should be utilized often. In Step 3 we are going to go a step further and tie all of the information we鈥檝e learned in Steps 1 & 2 and tie聽 Truffle + Infura + React together!聽