Solidity For Fun And Profit

A No-Nonsense Guide to Writing Your First ICO Smart Contract.


Let's cut to the chase: You've seen the rise and fall of countless Initial Coin Offerings (ICOs), and you want in on the action. There are so many amateurs getting rich from this new fundraising model, that you'd make a killing if you just knew how to write Ethereum smart contracts in Solidity. You might think that you need to be some sort of genius to learn how to do that, but let's set the record straight: You don't need to be a genius to write Ethereum smart contracts in Solidity. I knew nothing about Solidity before launching, one of the hottest cryptocurrencies on the internet[1], but I figured everything out in no time at all! And believe me, I'm no genius!

In this tutorial, we're going to build a pretty standard Solidity ICO contract from scratch. It will let investors buy a token with Ethereum and transfer their tokens to other investors. It will also conform to the ERC-20 standard (more on this later), allowing it to hook into the Ethereum token ecosystem. Finally, we'll look at a few ways to give your contract some extra flair. If you want to modify the code and interact with your contract as we go along, you can use a development tool like Truffle to compile your code.

This post will assume you have a general understanding of what Ethereum is. If you don't, the Ethereum Whitepaper is a great place to get your feet wet.

Let's get started!


Solidity Basics

Let's start with a Hello World contract, and go over some of its key features:

After the first few lines of the file (which specify the Solidity compiler version and provide a multi-line comment), this codes should look pretty familiar to developers with JavaScript experience. Contracts are essentially classes, and when you launch them their instances are accessible at Ethereum addresses. As we'll see, contracts have public and private functions, maintain their state with state variables, and can inherit from other contracts.

The other thing that jumps out is that everything in Solidity is statically typed, with the type coming before the variable definition. We have strings, bytes, booleans, and different sized ints and uints, all with the basic operators available in JavaScript. Additionally, Solidity has a special type to denote Ethereum addresses (ex. 0xcA5228D1fe52D22db85E02CA305cddD9E573D752).

Solidity also has a native mapping type, which stores key/value pairs of pretty much any type. Plus, it has arrays and structs to cover the rest of your data-modeling needs.

Read more about Solidity types in the docs.

In this example, we create a FastCashMoneyPlus contract and set several public state variables. totalSupply and fastCashBank (which represent the total outstanding balance of FastCash and the amount of unallocated FastCash, respectively) are left empty for now, while decimals and name are set to specific values. On line 14, we create a mapping of addresses to uints, representing the balance of each FastCash account. Finally on line 16, we define a constructor function (which always shares the name of the contract), and set totalSupply and fastCashBank to 1 million FastCash.

You might notice that something funny is going on regarding decimal places: Solidity doesn't have floating point numbers! If this is the case, how can we transact fractions of FastCash?? While it may seem a bit roundabout, the standard way to handle this is to specify a special decimals state variable that, as you might guess, indicates the number of "implicit" decimal places for your coin. This means that the smallest denomination of FastCash (which is called the MoneyBuck) is equal to 0.000000000000000001 FastCash, and that totalSupply equals 1000000000000000000000000 MoneyBucks!

Okay, now that we have the foundation in place, let's build some functionality to let people buy and transfer FastCash!


Buying Tokens

Next, we're going to write some functions to update the accounts being stored in the balanceOf mapping. Let's keep things simple for now by fixing the FASTCASH/ETH exchange rate at 2/1, and allowing the ICO to continue until there is no more FastCash left in the bank.

First we add a new state variable, centralBanker, and set it to msg.sender in our constructor function. msg is a reserved word in Solidity, and gives you information about the function invocation. Among other things, msg has a sender property that gives you the address that is invoking the function. In this case, msg.sender refers to the address that launched the contract. (We're going to need to hold onto this for later so we know where to send the ICO funds).

Next, we define a buy function on line 27. Since this function will be accepting Ethereum, we need to add special "modifier" called payable to it.[2] Now when someone sends Ethereum to this specific function, that amount will be stored in the contract's balance.[3] We can get a uint representation of this amount (denominated in WEI[4]) from msg.value, and plug it into a utility function (weiToMoneyBucks) to get the amount of MoneyBucks to credit our new investor.

Then we use a special built-in Solidity function, require, to check that the investor is trying to buy a positive amount of FastCash, and that there is enough FastCash left in the FastCash central bank to accommodate them. If either of these conditions evaluate to false, require will stop the function dead in its tracks.

After these checks, we can get down to business: we add some FastCash (or, more precisely, MoneyBucks) to the investor's account, and subtract it from the central bank. And then the most important part: We transfer the amount of Ethereum that we just received to the central banker with centralBanker.transfer(msg.value).[5]

Finally, we define a transfer function so our investors can purchase goods and services with FastCash and sell it to other investors. This looks pretty similar to the buy function: We check to make sure that funds aren't being transferred to an empty address, check that the transfer amount is positive, check that the sender has enough FastCash in their account, check that the result of the transfer won't cause any overflows[6], and adjust the account balances.


It looks like we're in pretty good shape! Investors can buy and transfer FastCash, and all of the proceeds go straight into our bank account! But hold your horses, we're not done yet! If we want to seamlessly hook into the rest of the Ethereum ecosystem, we need to make sure that it conforms to the ERC-20 standard.

ERC-20 Standard

"What the heck is the ERC-20 Standard?", you might ask. ERC-20 is a specific "Ethereum Request for Comment", and describes a standardized interface[7] that all Ethereum tokens should conform to. We're already most of the way there with our totalSupply, balanceOf, transfer, name, and decimals functions[8], but we need to add a couple more things.

Fortunately we only need to do three main things to reach ERC-20 compliance, the easiest of which is setting a symbol state variable to "FASTCASH" (on line 14). This gives us an official shorthand to refer to our coin, and can be used by ERC-20 exchanges like EtherDelta.

ERC-20 contracts also give token holders the ability to approve transfers from other parties. For example, let's say that I own 100 FastCash, and want to give my lawyer the ability to transfer up to 50 FastCash on my behalf. With an ERC-20 token, I would call approve, and give it my lawyer's Ethereum address and an amount (denominated in MoneyBucks). Later, my lawyer can call transferFrom with my address, the recipient's address, and the amount. If someone wants to see how much my lawyer is allowed to transfer on my behalf, they can call allowance with my address and my lawyer's address.

So if, for example, I get arrested at the Canadian border for securities fraud and don't have access to my FastCash or Ethereum wallets, my lawyer could bail me out with 25 of my own FastCash. But, if I never increase my lawyer's allowance and I get arrested at the German border for securities fraud (which has a bail of 30 FastCash), then I'd be 5 FastCash short of freedom.

Implementing these functions isn't much harder than everything else we've done so far. But first, let's extract all of our transfer logic into a private function, _transfer, on line 49, and give it the internal modifier. Now we can use _transfer in our external transfer function, and our new transferFrom function (line 72) without duplicating any logic.

The crux of approvals is creating a mapping called allowed, which links addresses to a nested mapping of allowances. To visualize things, the mapping might look something like this:

{ myAddress => { lawyersAddress => 50, secondLawyersAddress => 50 } }

The allowance function (line 90) is pretty straightforward, returning allowed[_owner][_spender]. Likewise, the approve function (line 84) just sets allowed[_owner][_spender] = _value. Finally, the transferFrom function (line 72) makes sure that the sender is authorized to send that amount, transfers the coins with _transfer, and decreases their allowance.

The last thing we need to do is define Transfer and Approval events. Events are signals generated by your contract, which things like dApps can listen for. We want these events to fire whenever transfers or approvals happen, so let's add them to the _transfer and approve functions.

And that's it! Now we have a pretty vanilla ERC-20 contract. Next, let's add a few more features to make the contract a bit more flexible.


Inheriting Permission

As the FastCash central banker, you don't currently have much wiggle room. The exchange rate is fixed, and you have no way of cutting under-the-table deals with institutional clients. Let's give you, the central banker, some special permissions. But our contract is already getting a little unruly, so let's see if we can split up the logic first.

Structurally, the big change here is creating a new FastCashMoneyPlusPermissions contract, and then having FastCashMoneyPlus inherit from it (contract FastCashMoneyPlus is FastCashMoneyPlusPermissions). This works similarly to inheritance in other languages, where FastCashMoneyPlus now has access to functions and state variables defined in FastCashMoneyPlusPermissions. As you'll see in some larger contracts, like the official FastCashMoneyPlus contract, the separation of concerns can be a bit more granular. But let's not worry about that for now.

The other big change is that now we define a onlyCentralBanker modifier on line 15. Modifiers have the ability to augment other functions. In this case, we're requiring the msg.sender to be the central banker. If this is true, then the underscore runs the function we're modifying. We can use this for our new function, setCentralBanker, which sets a new central banker if it's given a valid address. We don't want just anybody to be able to do this, however, so our onlyCentralBanker modifier ensures the only the acting central banker can call it.

Similarly, if we want a way to update the exchange rate we can extract an exchangeRate state variable from weiToMoneyBucks, and write an update function, updateExchangeRate, that only the central banker can call. And if we want to allow the central banker to distribute funds from the central bank at their discretion for market stability purposes, we can define a transferFromBank function (line 106) to do just that!

The interesting thing about using permissions is that it lets you structure your contract like an organization, where different addresses have different "roles". If you want to get fancy with it, you could conceivably implement a voting system where shareholders could vote on who has what role.

Keep in mind that there are no bug fixes or feature additions for contracts. By definition, the terms of the contract are set in stone once it's deployed to the blockchain. That being said, if you modularize your contracts and link them together, you can use permissioning as a way to safely swap them out.

One way to do this is to write a core contract that effectively acts as a controller, and defers to other contracts to implement core chunks of business logic. This way, if one of your features has a bug, you could deploy a new feature contract and point the core contract at the new contract. Here's an example of what that could look like:

Also keep in mind that permissions aren't restricted to humans: You can also give permissions to other contracts. This would allow you to invert the direction of control from the above example. Instead of allowing your core contract to act on child contracts, you could allow other contracts to act on your core contract.


Pretty cool stuff! But at the end of the day, investors don't care how flexible your code is -- they want to make money! Let's look at a few ways you can help them out with that.

Adding Pizzazz to Your Contract

After you have the foundation of your contract in place, you should think about what features you want to add to make your contract different. In the case of FastCashMoneyPlus there are two unique features.

First, investors have special referral codes linked to their accounts, which they can use to transfer FastCash and to receive a 10% FastCash referral bonus. That's right: when investors give their special referral link to friends and family, the investment console will pick up the referral code and forward it along to the official FastCashMoneyPlus contract. As you can see in official FastCashMoneyPlus buy function, it takes a _routingCode (which is generated by the investment console), and a _referal code (which is optional). The logic here is pretty straightforward. It registers the referral code (or, routingCode) with the investor's account if it does not already exist, and then it checks for a referral. If a referral is provided, it calculates a sale based on 10% of the MoneyBucks purchased, and credits the referrer's account.

Second, the price of FastCash is set to increase by 20% every week![9] You can see the precise logic in the official FastCashMoneyPlus getExchangeRate function. If it looks complicated... that's because it is. Since there are no decimal places in Solidity you can't just multiply a number by 1.2 -- you need to multiply it by 12 and then divide by 10. At the other end, the larges numbers supported by Solidity are uint256 (that's 77 zeros). That sounds pretty big, but when you're performing a compound operation on 1,000,000,000,000,000,000 MoneyBucks (i.e. 1 FastCash) over a 71 week timeframe, the numbers get very large very fast. In short, this formula of this function was derived using plenty of algebra to get rid of a bunch of extra zeros. You can read more about this in the Official FastCashMoneyPlus White Paper for more detailed information on the inner workings of the Official FastCashMoneyPlus contract.


Congratulations! You have reached the end of the official FastCashMoneyPlus Solidity tutorial! With the informaiton you've just learned, you're all set to start writing your own Ethereum smart contract in Solidity and MAKING MONEY from your very own ICO.

Please see the Official FastCashMoneyPlus Contract and Official FastCashMoneyPlus White Paper for more detailed information on the inner workings of the Official FastCashMoneyPlus contract.

To buy FastCash, please visit the FastCashMoneyPlus Investment Console. For all inquiries, please email [email protected].

[1] ^ The first two things people usually ask me when they visit is "How do I buy FastCash?", and "Is FastCash a real cryptocurrency, or is it just a flashy website?"[1b]. The answer to this question is a resounding YES! FastCashMoneyPlus is a real ERC20 token living on the Ethereum blockchain at 0xcA5228D1fe52D22db85E02CA305cddD9E573D752. If you don't believe me, you can even read the contract source code here.

[1b] Actually, the first two questions they ask are usually "Is this site going to give me a virus?" and "Why is this site eating up all of my CPU?". But since the answers to these questions are both clearly "No", they wouldn't make for a very interesting blog post!

[2] ^ Modifiers, as you might have guessed, modify the behavior of the function. We'll talk about defining our own modifiers later.

[3] ^ You can get the contract's balance with this.balance.

[4] ^ WEI is the smallest denomination of Ethereum, where 1 WEI = 0.000000000000000001 ETH.

[5] ^ Note that you can just as easily send Ethereum to any address.

[6] ^ This probably won't be a problem here, but it's always a good idea to make sure that you don't increment a variable beyond the amount it can hold.

[7] ^ Here is the specific interface.

[8] ^ Even though we defined some of these as state variables, Solidity will create getter functions for them.

[9] ^ You might also notice that the official weeksFromCreation function (which you can see here) makes use of the special now keyword to find the number of weeks since the contract launched.