There’s a lot of background and story in these first sections. If you’re a developer picking up Solidity and just skimming, you can get the most out of this article by scrolling down to the gotchas sections below.
I found this while googling for “Solidity” and with usage rights.
Cryptos and Ethereum are hot topics right now, and within tech circles, ethereum dapps (decentralized apps) development is just beginning to take off (in part due to the popularity/virality of CryptoKitties in December 2017).
Resources to learn about developing on the Ethereum blockchain is still all over the place. There’s tons of one-off articles (like this one) everywhere, about certain specific topics, but very few articles about the very beginning steps of getting started.
I started playing around with it a few weeks ago. My only regret is not writing down all of my learnings in real time as I go, because there has been so much to learn, and things that already seem like second nature to me now, were still extremely foreign to me a few weeks ago.
I’m starting now, and will also try to go back as far back as I can remember, to make note of all the gotchas I’ve had along the way.
Like many others, I started with the Truffle Framework. It’s a Node.js framework for developing Ethereum dapps. The other popular framework is populus, which is in Python. I don’t know much about it, so I won’t talk about it here.
The first question that comes up is what role does a “framework” play in Eth dev? I thought Eth dapps are written in their own language called Solidity (docs here), why is Javascript involved?
The first thing to understand then, is that Solidity code is compiled into binary code, in order to be executed on the Ethereum blockchain. The compiler is solc
. Having the Truffle framework mainly helps with two things: 1) Compiling and eventually migrating (deploying) your compiled smart contracts onto live networks (mainnet or a testnet like Ropsten/Rinkeby), 2) Writing and executing both unit tests and integration tests (written in Javascript, calling into your smart contract functions via web3 just like real world apps would).
Truffle comes with Truffle Boxes which are sets of templates you can start new dapps off from.
I chose to start with the Pet Shop, which also comes with a full tutorial article. I must stress that this tutorial is *excellent*. If you have absolutely no idea where to start — don’t go and read all the other articles others have written, like how to code your own CryptoKitties and so on. Read and follow this Pet Shop tutorial. (If you need help getting started with Node.js at all because you haven’t worked with it, I recommend my getting started with Node.js tutorial.)
The nice thing about this tutorial is it assumes almost no knowledge. It doesn’t assume knowledge of React. Only jQuery, which pretty much everyone knows at this point. And some minimal knowledge of Node.js.
Consider the rest of this article a “follow-up” to end of that tutorial — an attempt to rescue you when you feel lost after finishing that tutorial!
You will have a few things under your belt by this time. You have Ganache installed and running, which allows you to do local testing, both units/integration tests as well as end-to-end tests from the browser to the smart contract. You have your browser with MetaMask plugin for testing this on live networks (mainnet or testnet). You have your code editor (VS Code for myself), and terminal running truffle commands. All seems good.
Now you start exploring and making your first changes to the smart contract solidity code, and see how it all works out. You may immediately realize that even though the syntax of Solidity looks simple and looks like Javascript, it’s actually incredibly restrictive, because of memory and resources concerns.
Your experience might soon turn out to be the Pet Shop of Horror. Like the author of that article, I learn best by doing, instead of reading documentation. Also like the author, I ran into most of the same things mentioned on that article, and some more.
One of the first things I tried to do was trying to make my dapp take payment (in ETH, of course). After all, the purpose of most dapps is to involve an ETH payment somewhere in the functionality, right? (at least if you’re trying to make any revenue doing one.)
I was not able to find a single article or documentation page anywhere explaining how exactly you write your smart contract code AND Javascript code in order to take a payment from the user. (The Pet Shop tutorial doesn’t include it, neither does the Solidity documentation linked above
At the end, I only figured this out because I looked the source of another smart contract, that is simple enough (and has nearly no other functionality other than sending in ETH payments) to read and understand.
Below is an example Solidity smart contract that takes in payment:
pragma solidity ^0.4.19;
contract MySmartContract {// If this smart contract's purpose were to keep track of how// much ETH a user (an address) has sent inmapping(address => uint) public balances;
function MySmartContract() public payable {// constructor needs `payable` keyword.}
function() public payable {// fallback `payable` function is needed for a contract to// accept ETH payments.}
function sendEth(bytes32 message) payable public returns (bool) {// Here, the ETH value being sent is available as `msg.value`.balances[msg.sender] = balances[msg.sender] + msg.value;// This function also takes in a message that is 32 chars max.// Also returns a bool as an example.return true;}}
This is somewhat of a minimal working smart contract in Solidity that can take in an ETH payment (and do nothing to it other than keeping the money itself!).
There are already several sub-gotchas just from this code:
It doesn’t come in as a parameter of a function call. When searching or looking in documentation, you may quickly find the transfer
call. Trying to call transfer
will run into errors because what it does is send ETH money out of yourself (the contract) to others.
What should happen is that you need to make your function (and contract) payable
, then on the Javascript side we will look at how to trigger the call that has a ETH payment attached to it.
On the Solidity side, the amount that the user is sending, comes in as the msg.value
variable. (the msg.sender
variable contains the public address of the user.)
This is another subtlety you may not realize when you first start. If your assumption is that the smart contract is a computer program, and your users are users, you may not realize that the smart contract is also like a user on the Ethereum network, in that it can own an ETH balance (store money).
When a user sends an ETH value into your smart contract function, your smart contract now owns that ETH. If you want that ETH to eventually go into your wallet, you will need to expose a function, callable by only a certain person/address (yourself), which transfers everything the contract owns, onto yourself.
storage
“ type, and are permanent data stores.You may have learned that there are storage
variables and memory
variables. Variables initialized at the contract level are automatically storage
type. (Variables initialized at the function level are memory
type by default, but can be defined as a storage
type explicitly if needed.)
If you’re learning by examples, this has another implication, and you probably guessed it by now: This is how you store data on a smart contract.
Yes, there’s no fancy magic behind it. No database calls. If you develop a decentralized app, and you need to store some data on the blockchain, throw it onto a variable on the contract level.
The data types that will probably be most handy are array
s and mapping
s of uint
s and bytes32
s and address
es.
If you’re from the Javascript world, and you’re used to using literal objects as hash maps — the equivalent data type in Solidity is mapping
s.
Similar to languages like C++ and Java where you have generics, you have to define the data types for both keys and values of your mappings.
By far the most common data types you’ll use are uint
(for storing ETH values or any numeric values), bytes32
for storing characters/strings, and address
for storing user addresses (think of them like user IDs). There is also an actual string
data type, which is really a dynamic array of bytes
, which has limitations you’ll find out soon.
Now that you have the Solidity side of the code, let’s look at how you would make calls to it properly from the Javascript side, from your UI.
var message = 'Hello World!';var amountInWei = 1000000000000000000; // This is 1 ETH
mySmartContractInstance.sendEth(web3.fromAscii(message), {from: account, value: amountInWei, gas: 3000000});
For now, we assume the code before this is all set up with a web3.js
instance, and it’s hooked up with your deployed contract’s ABI file (a json file generated at the time of compiling/migrating to the live network). I’ll cover more details on that in a future section.
Let’s look at the sub-gotchas just from this piece of Javascript code.
This is something I wish there was an article telling me about; and I only figured it out after looking at an existing simple open source project.
The Javascript interface of the function always takes in the same parameters as you declared on Solidity side, but with an additional metadata object at the end which contains the “from” address (can’t be faked as far as I can tell), and the ETH value you’re sending in along with the call.
Armed with this, you can programmatically derive the value from whatever your app’s business logic is, and pass it into this call; and the user’s MetaMask instance will prompt them if they approve sending in that amount of ETH.
This won’t always be the gas amount the user actually has to spend. Most likely it’ll be little, if your smart contract doesn’t do a lot of looping and things that are costly in cpu resources. But you still have to specify a gas amount here nonetheless, or else it wouldn’t work. The user has the option to adjust it on their MetaMask prompt.
You may know by now that ETH has a word/term for different denominations of its currency. The smallest denomination is called a wei. You can find the full list here. The commonly used denominations seem to be wei (default for all code interactions), Ether, and Finney (0.001 Ether, or a milli-ether). I am guessing the idea is that when Ether is worth $1000 USD, a Finney is about $1 USD.
Strings are just not easy with Solidity. Strings themselves being dynamically-sized arrays make it not easy to pass back and forth between JS and Solidity, and between Solidity contracts themselves. When possible, using bytes32
is more reliable as it works across everything. But it does mean you have to use a converter function to convert a regular string into the right format, and back when you retrieve it from Solidity.
As you can tell so far already, even with just a smart contract as small as simply taking in an ETH payment and doing nothing with it, there’s already lots of gotchas if you’re coming from other languages, and don’t have good official sources of documentations/tutorials/examples to learn the conventions of doing these simple things.
I had to learn pretty much all of above through trial and error. I’m hoping this article can help others on the same path along the way, when they get to these parts.
There is certainly a lot more gotchas on the path of setting up a simple end-to-end working Ethereum dapp. In the next article I’ll write about the web3.js
set up / structure code with your client JS, and more interaction intricacies between Javascript and your Solidity code.