Useful Modules for Developing/Testing Smart Contracts

Seungwon Go
ReturnValues
Published in
7 min readDec 17, 2018

By Seungwon Go, CEO & Founder at ReturnValues (seungwon.go@returnvalues.com)

npm module에 대한 이미지 검색결과

truffle-flattener

truffle-flattener module takes all the files that are referenced in a solidity program and put them into one file.

You can install truffle-flattener using the command below:

npm i truffle-flattener --save

Now that you’re done with the installment, you can make a file that contains all the codes that are being referenced using truffle-flattener.

First, make a new folder with a name ‘flat’.

And run the command below in the terminal:

truffle-flattener ./contracts/SampleToken.sol > ./flat/SampleToken_flat.sol

If you run the command, it will load and show not only the contracts that are imported in SampleToken.sol but also all the contract codes that are referenced in the files that are imported and concatenate them into a file named “SampleToken_flat.sol” in a “flat” folder.

When you do “Verify and Publish” your deployed contract on etherscan.io, you’ll need all the codes in one file.

eth-gas-reporter

This modules calculates and reports how much gas is used for running the methods in the test cases and deploying the contract.

You can install it with the command below in the terminal:

npm i eth-gas-reporter --save

If you run the test case from “Truffle: Implementing Test Cases for Smart Contract”, you’ll see the report that shows how much gas is used for deploying the contract and running the methods used in the test cases.

Recently, I’ve run a program that deploys smart contract through web using web3. The gas needed exceeded the Block Gas Limit(4712388) on testnet(Ropsten) and I failed to deploy the smart contract.

By using eth-gas-reporter, you can estimate how much gas will be needed for deploying the contract and running methods used in advance, then you can modify your program before deploying.

solium

Solium is a module that checks the coding style and analyses security issues of your solidity program.

You can install it using the command below:

npm i solium --save

When you’re done with the installation, run the command below in the project root folder.

solium --init

You’ll see the two files have been created in the project root folder.

  • .soliumignore : contains names of files and directories to ignore while linting
  • .soliumrc.json : contains configuration that tells Solium how to lint your project. You should modify this file to configure rules, plugins and sharable configs.

.soliumrc.json file contains the code below:

{
"extends": "solium:recommended",
"plugins": ["security"],
"rules": {
"quotes": ["error", "double"],
"indentation": ["error", 4]
}
}

About the coding style rules, you can find them in the following link: https://solium.readthedocs.io/en/latest/user-guide.html#list-of-style-rules

Let’s check if our code meets the coding style rules using the command below:

solium -f ./contracts/SampleToken.sol

According to the result shown in the screen, it says we need to use 4 spaces for a tap in the solidity program.

Now open SampleToken.sol file and edit it so that the tap is four empty spaces and run the module to check if our program follows the coding style rules.

Then, you’ll see the message below:

About the security rules, you’ll find in the following link: https://www.npmjs.com/package/solium-plugin-security#list-of-rules

Using the command below, let’s check if our code follows the Security Rules:

solium -d ./contracts/

No issues have been found in our code.

solidity-coverage

Code coverage, meaning how much code has been covered, in software development is of the indexes that indicates how enough testing has been done. It means how much of the code has been actually executed when testing a software in development.

solidity-coverage is a module that measures code coverage of a solidity program. It measures in terms of Statement, Branch and Function.

Statement Coverage

  • Statement Coverage is satisfied if every line of code is run at least once.
function foo (uint x, uint y) public returns (uint)
{
uint z;
if ((x > 0) && (y > 0))
{
z = x;
}
return z;
}

When you call foo(1,1), the conditions (x>0) and (y>0) are both satisfied, which will run z=x; so all the lines will be run. So the test foo(1,1) satisfies Statement Coverage. However, the test foo(0,1) does not meet if condition, so does not satisfy Statement Coverage.

Branch Coverage

  • Branch Coverage is satisfied if the results of test cases are true and false.
function foo (uint x, uint y) public returns (uint)
{
uint z;
if ((x > 0) && (y > 0))
{
z = x;
}
return z;
}

foo(1,1) and foo(0,1) satisfy Branch Coverage. The first foo(1,1) will go through if statement and z=x will be run. But the foo(0,1) does not satisfy the condition (x>0) and z=x will not be run. Therefore, branch coverage is satisfied because when running foo(1,1), and foo(0,1), the results of the if statement satisfy true/false.

Function Coverage

Function Coverage checks if all the statement and the branch coverage are satisfied in the functions. So if any statement or branch coverage is not satisfied, function coverage is not satisfied.

Then, let’s install solidity-coverage using the command below:

npm i solidity-coverage --save

If you run the command below in the terminal, it will start analyzing the contract implemented in the contracts folder in four sections(Statements, Branches, Functions, and Lines) and will print out the result in the terminal.

./node_modules/.bin/solidity-coverage

And in the project root folder, you’ll see that coverage folder and coverage.json file have been created.

If you open the coverage/contracts/index.html in the browser, you’ll see the list of contracts we’ve developed in the contracts folder and the analysis result of each contract.

By clicking SampleToken.sol, you’ll see the source code and the result of the analysis. You need to be aware that it does not analyse the solidity files that are imported. So if you want a thorough analysis, you need to make one file that includes all the code used using truffle-flattener modules and analyse that file.

The image above shows the analysis result in four parts: Statement, Branches, Function and Lines. Let’s see the meaning of four parts:

  • Statements : they refer to the code lines in the functions except branches. In the code above, the line 12,13 and 14 belong to statements.
  • Branches : this is a section where it checks if certain conditions, such as if, assert, and require etc. are satisfied. In the code above, there is no Branches section.
  • Functions : this is a section that are declared as function, modifier or constructor. In the code above, there is one function, and it is from the 9th to 11th line.

In the coverage.json find created in the project root folder, you’ll find the analysis results of Statements, Branches, Function, and Lines of each contract.

  • path - The path to the file. This is an absolute path, and should be the same as the key in the report object.
  • s - Hash of statement counts, where keys as statement IDs.
  • b - Hash of branch counts, where keys are branch IDs and values are arrays of counts. For an if statement, the value would have two counts; one for the if, and one for the else. Switch statements would have an array of values for each case.
  • f - Hash of function counts, where keys are function IDs.
  • fnMap - Hash of functions where keys are function IDs, and values are {name, line, loc, skip}, where name is the name of the function, line is the line the function is declared on, and loc is the Location of the function declaration (just the declaration, not the entire function body - see 'Location Objects' below.) If skip is present and true, then this indicates that this function was ignored by a ### instabul ignore ... ### pragma. Note that if a function is not ignored the skip field will be missing entirely.
  • statementMap - Hash where keys are statement IDs, and values are Location objects for each statement. The Location for a function definition is really an assignment, and should include the entire function. In addition to the normal location object fields, a statementMap entry can also have an optional skip field.
  • branchMap - Hash where keys are branch IDs, and values are {line, type, locations} objects. line is the line the branch starts on. type is the type of the branch (e.g. "if", "switch"). locations is an array of Location objects, one for each possible outcome of the branch. Note for an if statement where there is no else clause, there will still be two locations generated. Istanbul does not generate coverage for the default case of a switch statement if default is not explicitly present in the source code.
  • l - Hash of line counts, where keys are the line number.

--

--