Writing Smart Contracts with Solidity > 0.5

Writing Smart Contracts with Solidity > 0.

5A brief walkthrough to start writing Ethereum smart contracts with Solidity 0.

5 and aboveRoss BulatBlockedUnblockFollowFollowingFeb 2Start writing smart contracts with Solidity > 0.

5This article acts as an on-boarding tool for you to start writing smart contracts with Solidity.

By using standard tools and conventions that the developer community have been evolving since the language’s inception, we will visit the recent changes to Solidity and how to ensure your smart contracts are error free.

The official Solidity documentation has fallen behind the times slightly, at least at the time of this writing — the examples are still showcasing Solidity 0.

4 (the current version introduces a collection of new features and breaking changes from the previous version) with out of date and somewhat uninspiring example contracts.

I find Truffle Boxes a more inspiring resource to browse through.

What we will cover here: IDEs & tools, importing and compiling contracts, breaking changes and conventions.

In this article we will firstly overview the IDEs at your disposal to be developing Solidity smart contracts, before visiting important concepts to adhere to when writing Solidity contracts, and how to ensure we utilise them correctly.

We’ll also visit the structure of a smart contract and popular conventions used when writing them.

If you would like to contribute to Solidity, documentation is one of the most requested aspects to be contributing to at this time.

Although contributing to the language is an entirely different talk, check out the Solidity Contributing page if you’d like more information on the subject.

With that, let’s start familiarising ourselves with Solidity 0.

5 and suitable software for developing with it — you will most likely be able to integrate Solidity development into your favourite IDE.

Prerequisite: Setting up your workspaceThere are a couple of notable browser-based IDEs that you can utilise to develop Solidity smart contracts in the event that you do not use a dedicated IDE: Along with the Remix online IDE recommended in the Solidity docs, we also have ETHFiddle (Similar to JSFiddle) that allows you to run contracts online and share them throughout your network.

IDE Solidity SupportI personally prefer installing support for Solidity in my favourite dedicated IDE, opting for Sublime Text over other offerings.

Let’s briefly visit some of the packages available for your IDE:Sublime Text: The Ethereum package is available for Sublime Text, as well as a linting package named SoliumLinter.

SoliumLinter is used to analyse your Solidity code and check for errors within the Sublime Text IDE.

Visual Studio: A Solidity package is available on the Visual Studio Marketplace, enabling Solidity smart contract development in the VS IDE.

Atom: The language-ethereum package is available for Atom bringing syntax highlighting and snippets to Solidity and Serpent files in Atom.

Emac: Enable Emac Solidity mode.

Vim: Enable Solidity syntax with vim.

Install the relevant package for you and fire up a new project.

The next tool we will visit is Truffle.

The Truffle Suite is a set of tools designed to aid in the entire Ethereum Dapp development process — but Truffle itself is very good at aiding in the development of Solidity Smart Contracts — this is what we will focus on in more detail here.

To get up to speed with Truffle and to save repetition, check out my introductory article on the suite:Introduction to the Truffle Suite and Dapp Development PipelineBreaking down the Ethereum Dapp Development pipeline using Truffle, Ganache and Drizzlemedium.

comUpdate to the latest Truffle and Solidity versionsIt is worth mentioning the importance of keeping Truffle and the underlying Solidity compiler up to date.

Run the following commands to install the latest versions of Truffle and solc (Solidity compiler) packages:npm install -g truffle@latestnpm install solc@latestTake note of the latest version of the Solidity compiler in-particularly to guarantee your smart contracts will adhere to the latest Solidity standards.

They change quite frequently!Exploring & Importing Solidity ProjectsAt this point you may wish to import some ready-made smart contracts into a Truffle project.

Let’s briefly do this now to get a feel for what completed contracts consist of, as well as familiarising ourselves with the import process.

MetaCoin — Basic Truffle ProjectA bare-bones project we can use for familiarisation purposes is the MetaCoin project, provided as a Truffle box.

Import the project in a new folder by unboxing MetaCoin with the following commands:mkdir metacoincd metacointruffle unbox metacoinThis bootstraps a Truffle project with the contracts/MetaCoin.

sol contract.

Not only is this contract written with Solidity 0.

4, it is also incomplete and does not adhere to the ERC20 standard; not very useful.

However, the contracts are valid syntax and will indeed compile.

Run truffle compile now to observe a successful deployment.

Take a peak at the MetaCoin.

sol file and see if you understand what is happening.

We will visit this syntax later on in the article in relation to Solidity 0.

5.

ERC721 Standard by 0xcertNext, let’s briefly visit a completed production-ready token, by importing the ERC721 standard into our project.

Check out the contracts here on Github or the project homepage here.

About the ERC721 standard:ERC721 contracts adhere to a standard for Non-Fungible tokens.

Every token is unique and could have a different value.

Use cases include collectables apps such as Crypto Kitties and similar offerings, whereby every Kitten is represented by a unique token ID.

Within the /src/contracts/tokens folder there is a basic NFToken offering as well as two extended contracts; one for additional MetaData, and one for Enumeration.

Contracts starting with erc721- contain function signatures required to adhere to the standard, whereas contracts starting with nf-token- are the actual implementations.

These contracts also import utilities from the utils/ and math/ folder one level up.

Let’s import the entire contracts/ folder within our Truffle project.

Clone the entire project outside of your local metacoin/ folder and copy the contracts into its contracts/ folder:#clone ERC721 project and copy contracts into metacoincd .

git clone https://github.

com/0xcert/ethereum-erc721.

gitcp -R ethereum-erc721/src/contracts/* metacoin/contractsIn order to migrate these contracts we will need to add a new migrations file.

Add a 3_deploy_nftoken.

js file within metacoin/migrations/, importing the MetaData NFToken contract for deployment:#metacoin/migrations/3_deploy_nftoken.

jsvar Migrations = artifacts.

require("Migrations");var NFTokenMetaData = artifacts.

require("nf-token-metadata");module.

exports = function(deployer) { deployer.

deploy(Migrations); deployer.

deploy(NFTokenMetaData);};And finally hop back into metacoin/ and migrate them:# migrate the contracts within metacoincd metacointruffle migrateExcellent, we already have some Solidity management workflow under our belt.

Let’s next talk about some underlying Solidity 0.

5 conventions.

Common Errors and Underlying Solidity ConceptsRunning various Truffle commands allows us to test our smart contracts in real time: truffle compile, truffle test or truffle migrate will all summon the Solidity compiler to compile the latest version of your Solidity contracts.

By utilising these features we can test the validity of our Smart Contracts and iron out bugs before they are deployed on our test blockchain, whether it be Ganache or any other client.

Now, if an error is found in your contracts, useful output is provided to us by the Solidity compiler, as well as suggestions on how to fix that error.

Let’s explore some Solidity errors you may encounter, and talk about the underlying concepts of Solidity we need to adhere to in order to prevent such errors.

These errors may range from any of the following:Forgetting to define a function as internal or external.

internal functions can only be called within the contract they are defined in (as well as by internal library functions and inherited functions).

external functions can be accessed by other smart contracts and via web3 calls, and consist of their own signature and address.

Forgetting to define a function type as view, pure or payable.

Functions need a type to determine their scope and capabilities in terms of what contract state they have access to, and what they can manipulate.

A function is of type view if no contract state is changed within that function.

In other words, it cannot alter the behaviour of future interactions with any contract.

They can only call other view or pure functions.

A function of type pure is even more restrictive; pure functions can only depend on the arguments passed into them.

Like view, they cannot utilise the msg object, send or receive ETH, or refer to the block object.

payable functions have the ability to accept ETH payments, and this could also be a payment of 0 ETH.

Providing an ETH amount of 0 will still be valid, the point here is that the function will accept this value and be able to process it.

Forgetting to provide a reference type to function arguments or function variables, as memory, callable or storage.

This is a requirement as of Solidity 0.

5.

These are called reference types, and arrays and structs now need a reference type applied to them.

A reference type is simply a reference to the data location of where the value is stored.

Arguments of external functions will be referenced as calldata.

An variable referenced as memory will indeed to stored in memory, making it temporary.

A variable referenced as storage will be stored permanently.

In practicality, function arguments are general memory whereas contract state variables and local variables are storage.

We now begin to realise the importance of a reliable compiler with reliable error reporting.

Truffle will provide us with this, letting us know where we have assigned the incorrect reference type, and which one to correctly use.

Not returning the correct type from a functionWithin Solidity we can either define a type of value (or tuple, or Struct) to be returned from a function, or the type followed by a variable.

For example:function ownerOf(uint256 _tokenId) external view returns (address _owner) { _owner = idToOwner[_tokenId]; require(_owner != address(0)); }In the above function we define the _owner return variable and simply write a value to it within the function block.

No return statemement is needed.

We could rewrite this function to just define the return type and include a return statement:function ownerOf(uint256 _tokenId) external view returns (address) { address _owner = idToOwner[_tokenId]; require(_owner != address(0)); return _owner; }Both cases are valid, and ultimately is the developers decision on which to use.

Overlooking illogical syntaxOnce we have carefully designed our smart contract along with our function signatures, we then need to be sure that the logic inside them do indeed adhere to the function’s type.

For example, we do not want to attempt sending a transaction from within a view function.

Luckily, attempting to compile contracts will fail if these errors exist.

The Solidity compiler will always pick up type errors.

Giving functions too much scopeConversely, giving a function too much capability that it does not use will flag a warning.

If a function is typed as payable but only adheres to a pure function, then the Solidity compiler will let us know and suggest the more suitable type.

Attempting things that Solidity does not support yetIf we attempt to return a type that is not supported within Solidity at this time, the compiler will fail and make it clear why.

For example, trying to return an array from a function is not supported.

Conversely, if Solidity does support such a feature, but such feature is part of an experimental feature set that you specifically have to define, the compiler will also let us know, and provide the line of code to be included at the top of your contract — most likely a pragma statement.

An example of this is constructing an array of a Struct type within a for loop.

General syntax errorsOf course, general syntax errors like spelling errors or missing semi-colons will be flagged, line number and code.

The Structure of a Solidity Smart ContractHow can we minimise the probability of introducing errors in our smart contracts beyond a distraction-free environment and a high dosage of coffee?.By making sure our contracts are organised and adhere to some sort of structure.

The high level structure of a smart contract in Solidity, with some example code, is as follows://Solidity versionpragma solidity 0.

5.

3;The version of Solidity being used is always a requirement.

//importsimport ".

/ERC721.

sol";import ".

/utils/supports-interface.

sol";import ".

/utils/address-utils.

sol";.

Imports of other contracts.

These may be utility or helper functions, for example, signatures for all the functions that adhere to the ERC721 standard.

//Contract Variablesaddress internal owner;mapping (uint256 => address) internal idToOwner;uint256 internal totalTokensMinted;.

Contract variables are defined next, storing contract state.

These can range from public addresses of other accounts, key value indexes with the mapping type, and primitive types like unsigned integers.

All the contract variables above are internal, meaning only contract functions can read and write to them, however this is not a requirement.

//Eventsevent TokenCreated( address indexed tokenAddress, string name, string symbol, address owner);.

Next we define the Events of our contract.

Events can be called from within our contract functions for the purpose of registering that something happened within smart contract execution.

This event is consequently recorded on the blockchain.

This allows external applications or APIs to listen to Events from the blockchain and update their UI or databases accordingly.

For example, A React app with web3 installed could listen to a Transfer event of an ERC20 token, and update its UI to reflect the balances of the sender and receiver.

Events can represent anything the developer chooses, and are dependant on the design of the contract.

//Modifiersmodifier isTokenAvailable(uint256 _tokenId) { uint256 tokenStatus = idToTokenStatus[_tokenId]; require( tokenStatus == 1, "Token is not available to transfer"); _;}.

function transferFrom( address _from, address _to, uint256 _tokenId ) external isAvailable(_tokenId) { .

}Modifiers are extensions of functions that execute before the function it is modifying in order to inject additional functionality, mostly in the form of checks and requirements of function arguments and contract state.

In the example above we are extending transferFrom() with the isAvailable() modifier to check if a token is available to transfer.

Within the modifier we use Solidity’s require() method, which reverts execution upon a condition not being met.

It also takes a second argument; a message to return upon a false result.

See the underscore and semi-colon below this require statement?: This is where the function we are modifying is executed.

We are essentially saying: I want this token’s status to be available before I execute transferFrom.

We can attach multiple modifiers to a function to check a range of conditions.

Modifiers keep our code clean and adhering to DRY (Don’t Repeat Yourself) principles.

Cutting down code will also save gas fees upon deployment.

//External Functionsfunction mint(address calldata _to, uint _amount) external payable { .

//call the internal minting function _mint(_to, _amount);}External functions can now be defined.

As we mentioned earlier on, external functions can be called from other contracts and public addresses.

In the above example we define a mint() function.

mint() handles the arguments needed to mint a token.

It is payable and receives ETH in order to do so.

Once the conditions are verified, mint() then calls an internal function, _mint(), in order to carry out the actual minting.

Why would we have multiple mint()’s consiting of internal and external functions?.Well, I may wish to mint tokens in different ways.

A mint(address _to) function could accept one recipient, whereas a mintMultiple(address[] _to) would accept an array of addresses, which would be looped through, but still utilise the same internal _mint() function to do the actual minting to the addresses.

//Internal Functionsfunction _mint(address[] calldata _to, uint _amount) internal { .

//call the internal minting function _mint(_to, _amount); emit TokenMinted(_to, _amount);}And finally, internal functions can be defined within our smart contracts.

An emit statement is also included here, showing that an Event can be emitted within a function.

Commenting syntaxBefore wrapping up this talk on Solidity 0.

5, it is worth mentioning commenting syntax that the Solidity compiler can also pick up and warn you about in the event your comments are not adhering to the expected conventions.

Take the following example from the ERC721 basic token transferFrom() method:/** * @dev Throws unless `msg.

sender` is the current owner, an authorized operator, or the approved * address for this NFT.

Throws if `_from` is not the current owner.

Throws if `_to` is the zero * address.

Throws if `_tokenId` is not a valid NFT.

This function can be changed to payable.

* @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else * they maybe be permanently lost.

* @param _from The current owner of the NFT.

* @param _to The new owner.

* @param _tokenId The NFT to transfer.

*/function transferFrom( address _from, address _to, uint256 _tokenId).

Notice the following conventions here:@dev is used to signify a comment for developers of the contract@notice is used to signify important warnings about function usage@param is used to outline each argument of a function.

If we document an argument that does not exist, the Solidity compiler will warn us about this.

@return is used to document the return type of the function.

The above function does not return anything, therefore @return is not used.

Where to go Next?I hope this article has given you enough to whet your appetite for writing Solidity contracts.

The official Solidity documentation does indeed go into the details and underlying workings of the language in a far greater depth than this article.

Even though the examples are out of date it is a valuable, free resource for delving into Ethereum smart contract development.

After reading this article familiarising yourself with the documentation should be more of a breeze, starting with the introduction:Introduction to Smart Contracts — Solidity 0.

5.

3 documentationA contract in the sense of Solidity is a collection of code (its functions) and data (its state) that resides at a…solidity.

readthedocs.

io.

. More details

Leave a Reply