Trang chủ‎ > ‎IT‎ > ‎Blockchain‎ > ‎

Smart Contracts

Introduction to Solidity Programming and Smart Contracts (For Complete Beginners)

Okay wait, slow down… What exactly is solidity and what makes these contracts so “smart”?

Solidity is a brand new programming language native to Ethereum, the second largest cryptocurrency by market capitalization, initially released in 2015. Ethereum is not only a cryptocurrency capable of storing value or making payments, but a fully fledged platform for creating what’s known as a smart contract.

For all intents and purposes, a smart contract is a programmable escrow of sorts, an independent middleman or a fair judge capable of managing a financial transaction between various parties and autonomously arbitrating a dispute.

What does this all mean?

Say a grandfather who is in his last years wants nothing more than to have his inheritance delivered down to his family through means of a will when he passes. In a traditional will, it would be clear who gets what, how much and when, solidified in a legally bound document. When the time comes to actually distribute the sauce, a judge from a court of law needs to revise the document and make decisions accordingly. A common problem that arises within families is an argument about who gets what, creating tension at best and destroying relationships at worst. During the court hearing, This could influence the decision of the judge, which in turn could produce unfair results and possibly create further damage to family bonds.

So that being said, what if we could streamline this process by drastically reducing this problem?

If the will was a smart contract, a judge would not be necessary. Here’s where it gets awesome. Gramps can actually make the contract hold assets on his behalf, and have them programmatically released to his liking after his passing. In this scenario, the code written in the contract itself would dictate the outcome, effectively eliminating the need for an arbitrator. Sarah gets $10,000, Ben gets $5,000 and Julia gets $2,000. The code executes and the assets in the form of a token or cryptocurrency get automatically distributed to these parties without the need for human intervention. While everyone involved may not be happy with the outcome, nobody can really argue with lines of code on a screen. Sounds practical, right?

Keeping this example in mind, let’s get to the part you’ve all come here for. In this lesson we will build gramps a simple will through a smart contract written in solidity.

Set up the Environment

Head over to Remix. This will serve as the development platform for writing your first smart contract. Your screen should look like this or something similar:

Head over to the top left dropdown “Environment” and make sure “Javascript VM” is selected. This means that all the code will run as a standalone, and not affect the actual Ethereum network in any way. Click the + icon in the top left corner to create a new file, and call it “will”. A tab will appear at the top which represents which file is currently being edited.

2. Define the Version

In solidity, the first line must always state its current version. Is should look like this:

The current version at the time of writing is 0.4.24

3. First Contract

Skip a line and type the following:

Each new contract must be prepended with “contract”, then the name with the first letter always capitalized, followed by open/close curly brackets to contain the logic. Use a double forward slash to write a comment, which is useful for describing for what the code does without altering it.

4. Global Variables and the Constructor

Before we start writing code, we should already have the terms of the will clearly defined. Let’s say gramps is leaving behind a fortune of 50 Ethers. 20 will go to his son Conrad and the remaining 30 to his wife Lisa. Realistically, when gramps passes away, an external program would call a function inside the contract to distribute the funds, but we will take care of that ourselves for the purposes of this tutorial. At the end of this article I’ve included a suggestion as to how this could actually be done!

Let’s start by declaring the owner of the contract, the amount of fortune left behind, a switch that tells us if gramps is still alive, and a constructor function that sets these values.

Line 5 declares the owner. When declaring variables in solidity, they must be prepended with their type. Owner in this case is of type “address” which is unique to solidity and represents an Ethereum wallet address. This will be useful later on when calling specific functionality only meant for the owner (gramps).

Line 6 will hold the value of the fortune gramps is leaving behind. Its type is a uint or “unsigned integer” which means it can only be a positive number. Solidity has many types, but we will not cover all of them here. They can be fod in the official documentation for further reading.

Line 7 tells us whether gramps is deceased or not in the form of a boolean value, true or false. It is set to false by default.

Lines 9–13 is the constructor function. This special function will execute automatically upon the contract’s deployment.

The “public” keyword is what’s known as a “visibility modifier” which tells the contract who is allowed to call the function. Public means that the function can be called within the contract and outside of it by someone else or another contract.

The “payable” keyword is what makes solidity truly unique. It allows the function to send and receive ether. The constructor has this modifier so that when we deploy the contract we can initialize it with an ether balance, in this case 50. When the contract receives ether, it will store it in its own address.

Here, we set the owner to “msg.sender”, which is a built-in global variable representative of the address that is calling the function. In this case, it will be us (gramps).

The fortune is set to “msg.value”, which is another built-in variable that tells us how much ether has been sent.

Even though isDeceased is set to false by default, it’s set manually here to provide clarity.

5. Modifiers

Modifiers are add-ons to functions that contain conditional logic. For example, I have a function that turns off a light switch and a modifier that states the light switch must be “on”. I add the modifier to function so that it can only be called if the switch is “on” and will throw an error if the switch is “off”.

Line 15 declares the “onlyOwner” modifier. If added to a function, it can only be called if the caller (msg.sender) is equivalent to the owner variable as stated above (remember how we set the owner in the constructor). We will need this to allow the distribution of funds, which will be implemented later.

The “require” keyword states that everything written within the following parenthesis must be equal to true or else solidity will throw an error and the execution will stop.

The “_;” at the end tells the execution to shift to the actual function after it’s done reading the modifier.

Line 20 declares the “mustBeDeceased” modifier. Once added to a function, it can only be called if “isDeceased” is set to true. We will also use this to allow for the distribution of funds. There is currently no way to set it to true, but we will fix that later.

As an aside, we could just write “require” underneath each function declaration, but using modifiers is a great way to avoid repetition and to reuse code.

6. Inheritances

Now we must declare how the loot is divided amongst the family members. We will need their public wallet keys (addresses) and their desired allotments.

As we stated before, Conrad will receive 20 ETH and Lisa will inherit 30. Let’s create a list to store their wallet addresses and a function that sets the inheritance for each address.

Line 25 declares an empty array called “wallets” for storing the family members’ wallet addresses. This is a list-like data structure in which any element can be indexed and subsequently accessed within it. The square brackets after “address” indicate it’s an array of items rather than a single variable.

Line 27 creates a mapping from an address type to a uint type named “inheritance” for stashing the value of each address’ inheritance. This is a key/value pair data structure in which the key can be called to obtain the value. It’s the equivalent of a “dictionary” in other languages such as Python and Javascript.

Line 29 declares the function that adds an address to the array we just created, then sets the inheritance given the address. When we call it, we must provide it with one family member’s wallet address along with their allotted spoils. Notice the “onlyOwner” modifier we added to this function. Can you guess why we stuck that in there? (Hint: look at the “public” keyword.)

Line 30 simultaneously creates a wallet address and appends it to our “wallets” array given the input parameter “_wallet” with “.push”. (Note: use of the _underscore_ is for stylistic purposes and has nothing to do with functionality, though many developers prefer to use this convention with input parameters for the sake of consistency.)

Line 31 takes the value of the key “_wallet” (a parameter) from the “inheritance” mapping we created earlier and sets it to the inheritance given the other parameter, “_inheritance”.

Notice how logically these steps connect starting from the first. We created a spot for the wallets and the inheritance to live. The function would then populate those data fields with the information we supply it!

7. Show me the Money

Let’s recap. So far we’ve learned about global variables and their types, the constructor, special keywords such as “payable” and “public”, built-in variables like “msg.sender”, modifiers and “require”, arrays, mappings and functions. We’ve built the framework, now let’s tie it all together so we can complete our contract.

For the last coding part of the tutorial, we’ll implement a way the family can get paid by looking through each of their addresses and sending them their respective dough.

Line 34 declares the “payout()” function. Note the “private” keyword. This visibility modifier is the opposite of “public” as we’ve seen earlier on. It permits this function to be called only within the contract as demonstrated on line 42. Security is the primary purpose as it doesn’t allow anyone or any other contract to interact with it. Notice the “mustBeDeceased” modifier tagged on at the end. Its currently still impossible for this function to execute because of it.

Line 35 is a for loop that iterates over the “wallets” array. The syntax is as follows: Declare a counter variable (i), state the loop’s condition and increment (i) every time one cycle is complete. The code within the block will execute up until the counter is less than the length of the “wallets” array. (i) will start at 0 as stated, the logic will execute, (i) will increment to 1 and the logic will execute again. The cycle repeats until the condition is satisfied. Can you guess how many times it will complete the task? (Hint: look at the array’s length)

Line 36 is the actual task we’ve been ranting about the entire lesson. “wallets[i]” refers specifically to the element located at the i’th position in the “wallets” array. During the first iteration, we know that (i) is equal to 0. We can thus surmise that we want the first address in the list, as arrays always start at index 0. We then introduce a new call to “.transfer()” on the address we just captured. This is one relatively straightforward global method to transfer value that’s embedded within Solidity. It only takes one argument, the amount we want to send. Being the savvy programmers we are, we came prepared with a data structure that contains the information in question. Can you remember where we kept it? “inheritance[wallets[i]]” refers directly to the amount of inheritance we specified in the “inheritance” mapping for again, each element located in the i’th position in the “wallets” array. Since i= 0 on the first iteration, we want the inheritance of the first address in the list.

To summarize, this single line of code transfers funds from the contract’s address to a receiver’s address which is pulled from a list with an amount equivalent to that same address’ inheritance allocation.

Lines 40–42 is the function that gets called when gramps passes away. Here, we set the value of the variable we declared right at the beginning, “isDeceased”, to true. Notice the repeated use of “public” and “onlyOwner” keywords. Bearing that in mind, we can finally call “payout()” to send forth the capital.

For the keen eyed readers, you may be thinking “isDeceased” is redundant. Technically you’re correct. We could eliminate “deceased()” all together and change “private” to “public” & “mustBeDeceased” to “onlyOwner” in “payout()”. It would produce the exact same results. This switch simply aims to explore another means of implementation in which we practice utilizing modifiers. It’s common practice to make functions private and have them called by a public function elsewhere for security purposes.

And we’re done!

Actually, not quite…

This smart contract is complete, but how do we actually use it? Now we can harvest the fruits of our labour.

8. Contract Deployment & Interaction

Your screen should look like this:

Head over the Compile tab in the top right corner and click Start to Compile.

You should see a blue box from Static Analysis. You are welcome to investigate further, but feel free to ignore it for now. Head back to Run.

Ensure “Javascript VM” is selected for “Environment”. Under “Account”, clicking the dropdown menu will reveal 5 addresses, each with a 100 ether balance. Select the first one.

Deploying a contract to the Ethereum blockchain isn’t free. The deployer must pay a nominal fee known as gas. Such a system is put in place to prevent people from spamming the chain with infinite loops using all the network’s resources without repercussion. If you wish to know more, MyEtherWallet has a comprehensive article on the subject.

Leave the “Gas Limit” field as is.

The “Value” field indicates the amount of ether we want to initialize the contract with when we hit deploy. Enter in 50. Remember how we added a “payable” modifier to our constructor early on? Go ahead and hit “Deploy”.

You should notice 3 things right away. First of all, the balance of the selected account should now read 49.9999… This is due to the 50 ether we gave to the contract, plus the small fee for deploying it. The console at the bottom will also provide additional details about the deployed instance, feel free to inspect it. The main thing to realize is this:

This is our contract instance! It generates its own address and displays the two public functions we created. As the owner, the first thing we want to do it set the inheritances of Conrad (20) and Lisa (30). Let’s say that Conrad’s address is the second one in the dropdown, Lisa’s the third. Select the second one, copy it by clicking the clipboard icon and paste it into the field above.

Before we execute, there are a couple of things to keep in mind. If you try to click the shiny button, it will fail. Can you guess why? (Hint: look at our modifiers.) The other caveat here is in the amount. When working with Ether, contracts read the numbers in Wei, which is a tiny fraction of Ether. So tiny in fact, that one Eth is equal to 1x10¹⁸ Wei. (That’s 1,000,000,000,000,000,000). Luckily, theres a tool that does the conversion for us.

Separate the address by a comma and paste in the value of 20 Ether in Wei. To answer the above question, make sure the first address in the dropdown is selected, not the second. Any other address won’t work because of the “OnlyOwner” modifier! (Whichever one is selected during deployment is crowned owner due to “owner = msg.sender”)

Let’s launch the rocket and repeat the same steps for Lisa. You should see the console outputting success messages. Inspect them and look for a section labeled “decoded input”.

As you can see, it displays the inputs we provided it.

The estate is set, but the sad news is in. Gramps has passed away of a heart attack during an arctic exploration expedition at the age of 73. He was an ambitious man, always full of energy. He grabbed life by the balls at every corner and didn’t take no for an answer. This dude even invested in crypto during the 2017 bull run and made some bank. He knew this day would come so he packed his winnings into the will and wished a prosperous life to his loved ones.

As we commemorate the death of a great man, we also call “deceased()” in his will. The console will smile, and the addresses will increase in balance. Keep in mind here that the account will have to spend some gas to execute the function. Open the dropdown menu and indulge in your success. Yes, you’ve just created your first fully functional smart contract! Go treat yourself to some ice cream, you deserve it!

If you’ve made it this far, you yourself are an exceptional human being. Maybe by the time you hit your last days, this technology will be mainstream and you can create your own an autonomous estate manager for your loved ones.

To terminate this tutorial, we must discuss one last question, one you may have been wondering throughout the journey. How on earth is gramps suppose to call the function if he’s dead?!? A futuristic solution would be to somehow have an IOT device that can remotely track a heartbeat that would have the power to execute the function if the beat stopped for more than x amount of time. Any other solution you can think of? Post it in the comments!