Share and get +16 +16

Introduction: Smart Contract Development

This is a guest post by KC TAM on Using Various Tools for Smart Contract Development: Remix, Web3 on TestRPC.

I recently read a good article on Blockgeeks, in which Ameer is trying to put everything about coding Decentralized Applications into one masterpiece. What a very ambitious and great work it is! Of which there are several components, and I would like to elaborate a bit on some of these tools, and how they can be used for contract development.

This series of article is not for Smart Contract 101 or Ethereum platform. You definitely can find a lot of good material in Blockgeeks. But I am sure by going through this, you will grab some ideas on these tools and hope this helps when you are working on the Smart Contract with Solidity.

I will first make a quick description of the Smart Contract I have chosen. And later deploy this contract in four environments. Here is a quick summary of the four environments we are showing here.

A Simplified Flow of Contract Compilation and Deployment

The Sample Smart Contract: Revenue Sharing

This application is taken from the Smart Contract in Chapter 4: Ethereum Accounts from the book “Blockchain Applications a Hands-On Approach” by A. Bahga and V. Madisetti. It has been modified to match some requirement on the latest release of Solidity.

This application is called Revenue Sharing. In short, a list of addresses is given when the contract is deployed. Anyone can send a certain amount of money (here it is ethers or ether’s denomination) and this amount of money is equally distributed to the addresses on the list. It is a rather simple Solidity contract.

Here is the Solidity of the Smart Contract.

pragma solidity ^0.4.8; contract RevenueSharing { address public creator; mapping(uint => address) public shareholders; uint public numShareholders; event Disburse(uint _amount, uint _numShareholders); function RevenueSharing(address[] addresses) { creator = msg.sender; numShareholders = addresses.length; for (uint i=0; i< addresses.length; i++) { shareholders[i] = addresses[i]; } } function shareRevenue() payable returns (bool success) { uint amount = msg.value / numShareholders; for (uint i=0; i<numShareholders; i++) { if (!shareholders[i].send(amount)) revert(); } Disburse(msg.value, numShareholders); return true; } function kill() { if (msg.sender == creator) selfdestruct(creator); } }

Some quick points about this contract

The contract is named RevenueSharing.

Function RevenueSharing() has the same name of the contract itself. It is the constructor, and only called once when the contract is deployed. We see in this contract an array of addresses is supplied, and this array of addresses are stored in another array called shareholders.

Function shareRevenue() is the only main function in this contact. When executing this function with an amount of ethers (in msg.value), the amount is divided into the number of shareholders (numShareholders), and each address in the shareholder array will get the portion. We will execute this function in our demo.

Function kill() is used for removing the contract. We will not use this function in the demo.

Note that all variables are defined with public. This helps us to observe more detail in the contract. In real life, we should be careful when making variables or functions public due to security consideration.

Remix

Overview

Remix is a suite of tools to interact with the Ethereum blockchain in order to debug transactions (directly quoted from here). There is an IDE version (Remix IDE) and an online version, which we will use here.

There are many tools inside Remix, but the following tools are of our interests,

Solidity Compiler. which generates a lot of useful information that we will use in another environment

Runtime Environment. Remix provides three: Injected Web3: to provider such as Mist or MetaMask Web3 Provider: to local host through ipc JavaScript VM: a simulated environment



Among the runtime environments, we are using JavaScript VM. In the JavaScript VM, Remix comes with five Ethereum accounts, each of which is deposited with 100 ethers. This is good enough for testing our smart contract. Also, mining is not required as it is done automatically.

You can easily access Remix from any browser (url: http://remix.ethereuem.org). This is a screenshot of Remix.

The screen is divided into several areas.

Area for Smart Contract: we are pasting the Solidity code of contract here.

Area of Compilation and Runtime: in Compilation tag, here show any compilation errors or warnings. in Run tag, we deploy the contract and execute contract functions.

Area of Transaction Logs: all transaction detail can be observed here.

Compile the Contract

We paste the Smart Contract code in Remix.

We notice that the code is automatically compiled, and there are some warnings. As they are not critical errors, we are safe to moving forward.

If we click Details, we will see a lot of information for this contract. Among them they are,

Bytecode

ABI

Web3 Deploy

They are needed when deploying this contract in another environment. We will refer this back later.

As we see no errors after compilation, we can run this contract onto Remix JavaScript environment.

Deploy the Contract

1. A Glimpse inside Run Tag

It is how it looks like inside the Run tag.

From the Environment, choose JavaScript VM.

After selecting JavaScript VM, we will see some accounts are populated in Account fields.

And as said, each of which are pre-deposited 100 ethers, just for testing. As we will use these accounts later, we can copy them first.

The Gas limit is to specify how much gas we can spend on any transaction. As we are in test environment, we do not worry this too much. I have tried some big contract deployment and the default gas limit is not adequate. Anyway, it can be increased to whatever value when needed.

The Value part is where we send the amount of ethers during contract deployment and executing a function. In our case, we do not put any value in contract deployment, but put some ethers when executing the function. See below for more detail.

2. Deploy the Contract

Now we see the contract RevenueSharing is already selected (we have only one contract in our code). We will use Create button to deploy this contract onto the JavaScript VM.

Something is required, as hinted in the input area: “address[] addresses”, when the contract is deployed. Remember this contract requires a list of addresses as sharing targets? For demo purpose, we will use the 3rd, 4th and 5th addresses listed above as the address list. So paste this beside the Create button:

Now make sure we have selected

Environment: JavaScript VM

Account: the first account when deploying this contract (begins with 0xca3…)

Paste the address array above beside Create button

By pressing Create we will see the following happens.

3. After the Contract is Deployed

The contract is now deployed in JavaScript VM (memory), and the contract address is shown (0x692…). We do not use this address in our demo. That address can be referred in other cases when needed.

Also, we see the variables marked as “public” is now shown, they are,

shareholders

numShareholders

creator

And two functions we have defined in this contract,

shareRevenue()

kill()

Before everything, we observe that the account balance is reduced by a small amount of ethers. The difference (417,626 weis, 1 wei = 10-18 ether) is the cost of deploying this contract. In real life, it is the real ethers deducted from your account when you deploy a contract.

Interacting with Deployed Contract

1. Check Variables

We can first check the variables by pressing the variable buttons. Here we examine the numShareholders and creator. For shareholders, as it is an array, we need to specify an index (0, 1 or 2), corresponding to the addresses we put when the contract is deployed (created).

All the variables are as what we expect.

2. Execute shareRevenue() Function

Now we execute shareRevenue(). We use the first account to deposit 30 ethers when executing this function (This is only for this function. In many cases this is not required.). According to the contract logic, the 30 ethers are to be distributed among the account list, that is, the 3rd, 4th and 5th account in our account list. As of now, the balance of each of them is still 100 ethers.

We use the same place to execute the function. Here we make sure to,

in Account field, choose the first account (begins with 0xca3…)

place 30 ethers in the Value

Then press shareRevenue.

After the function is executed, we examine the balance of each accounts, and see if it is executed according to our design.

First, we see 30 ethers are deducted from 1st account, and all the three accounts on the list now have 110 ethers. So the 30 ethers deducted from 1st account is now distributed among the three accounts. This part works perfects according to the contract.

Also, if we closely examine the balance of 1st account, some additional amount of ethers is deducted. The difference is 47,776 wei, which is the cost for this transaction. Every transaction, execution of function, or deployment of contract costs you some amount of ethers.

Transaction Log

We have not touched the transaction log during our test, but everything is kept in log, even the inquiry of a variable. Let us take a look on detail from two selected logs.

1. Contract Deployment

We can see who has deployed this contract, the contract address, and the transaction cost required to deploy it.

2. Execution of shareRevenue() function

Again we see it as a transaction cost. In shareRevenue(), there is a return boolean value and we see the “decoded out” there is a “true” return. Also, we have an event for successful distribution and we see it inside “logs”.

Summary

This is how Remix helps in testing the code we develop. It comes with very handy features and intuitive user interface. In next article we will use another environment, testrpc, to work on the same contract and see how it works.

The Best Tools for Smart Contract Development Part 2: Web3 on TestRPC

Overview

TestRPC is a simulation of an Ethereum blockchain, which comes with 10 pre-defined Ethereum accounts and supports mnemonics (that is, one can generate the same set of accounts with the same set of mnemonics). It does not come with a User Interface as Remix, and we need node console plus the web3 library to interact with this blockchain.

Preparation

The demo is done through command line or terminal. Use a terminal tool that supports screen spliting. I am using iTerm2 on my Mac.

Install node and npm: please refer here for installation on your platform.

Remark: I recently found that when installing web3 with npm, the 1.0.0 beta version is installed, where the commands used before (based on 0.20.4) do not work. Therefore we instead specify the version of web3.

All commands below are in version 0.20.0.

Open a terminal and split the screen into two. The left side is the node console, where we will work most of our time. The right side is where we run the TestRPC.

Start TestRPC

On the right side, start the TestRPC



Here we have some observation

TestRPC is a node application simulating an Ethereum blockchain in memory.

10 accounts are pre-defined.

These accounts are generated through mnemonic, and are different every time when TestRPC is started. To keep the same set of accounts, we can use the mnemonic shown above as parameters when running TestRPC.

Also, the RPC is opened on localhost:8545. Web3 is accessing the blockchain through this.

We will not touch on this part anymore, assuming everything is working fine in this Ethereum blockchain. Now we more focus on the node console (left side). During the test, we keep seeing commands and logs issued to the blockchain displayed on the TestRPC side.

Web3 object

We need to instruct node console we are using web3 and pointing the blockchain web3 is interfacing.

which is exactly the accounts created in TestRPC.

A Handy Function Showing Balance

I have found a handy function (link) that can show balance for all accounts. Here is the function.

Simply copy-n-paste this function into node console. Now we can call the function checkAllBalances() at any time, and it will show up the balance of all accounts in ether. Note that this function will be gone after we quit the node console, but we can add it back at any time needed.

Deploy the Contract

1. Compiling the Contract

Now everything is ready. We can deploy our Revenue Sharing contract.

We need to reopen the Remix as we are leveraging the compiler on Remix. After we paste the contract code in Remix, it is automatically compiled. Here we are using the result of contract deployment.

Click Detail on Compile Tag, and there is a lot of information there.

Among the information, three are of our interests: bytecode, ABI and Web3Deploy

The bytecode is the binary version of our contract after compilation and the instruction set to be run in Ethereum Virtual Machine (EVM), and the ABI (application binary interface) is the interface we are interacting with the contract bytecode.

Remix is kind enough to prepare the code in Web3Deploy, in which the bytecode and ABI are already included in the commands. Therefore we just need to use the Web3Deploy part.

2. Deploy the Contract

First, as required by the contract, we need to define a list of target accounts. For demo purpose, the three accounts starting from the second account are used, that is, from eth.accounts[1] to eth.accounts[3].

Then we follow what Web3Deploy suggests.

Create a class for revenue-sharing contract based on the ABI. Simply copy that line from Web3Deploy.

node console > var revenuesharingContract = web3 . eth . contract([{ "constant" :true, "inputs" :[], "name" : "creator" , "outputs" :[{ "name" : "" , "type" : "address" }], "payable" :false, "stateMutability" : "view" , "type" : "function" },{ "constant" :false, "inputs" :[], "name" : "kill" , "outputs" :[], "payable" :false, "stateMutability" : "nonpayable" , "type" : "function" },{ "constant" :true, "inputs" :[], "name" : "numShareholders" , "outputs" :[{ "name" : "" , "type" : "uint256" }], "payable" :false, "stateMutability" : "view" , "type" : "function" },{ "constant" :true, "inputs" :[{ "name" : "" , "type" : "uint256" }], "name" : "shareholders" , "outputs" :[{ "name" : "" , "type" : "address" }], "payable" :false, "stateMutability" : "view" , "type" : "function" },{ "constant" :false, "inputs" :[], "name" : "shareRevenue" , "outputs" :[{ "name" : "success" , "type" : "bool" }], "payable" :true, "stateMutability" : "payable" , "type" : "function" },{ "inputs" :[{ "name" : "addresses" , "type" : "address[]" }], "payable" :false, "stateMutability" : "nonpayable" , "type" : "constructor" },{ "anonymous" :false, "inputs" :[{ "indexed" :false, "name" : "_amount" , "type" : "uint256" },{ "indexed" :false, "name" : "_numShareholders" , "type" : "uint256" }], "name" : "Disburse" , "type" : "event" }]);

Now deploy the contract with the bytecode, plus the necessary information. Again, we can copy that line from Web3Deploy. The deployed contract is an object called revenuesharing.

node console > var revenuesharing = revenuesharingContract . new( addresses, { from: web3 . eth . accounts[ 0 ], data: '0x6060604052341561000f57600080fd5b60405161049d38038061049d833981016040528080518201919050506000336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508151600281905550600090505b81518110156100f957818181518110151561009157fe5b906020019060200201516001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808060010191505061007a565b50506103938061010a6000396000f30060606040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806302d05d3f1461007257806341c0e1b5146100c757806368eca613146100dc578063ab377daa14610105578063e579a0bd14610168575b600080fd5b341561007d57600080fd5b61008561018a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156100d257600080fd5b6100da6101af565b005b34156100e757600080fd5b6100ef610240565b6040518082815260200191505060405180910390f35b341561011057600080fd5b6101266004808035906020019091905050610246565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610170610279565b604051808215151515815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561023e576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b565b60025481565b60016020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060006002543481151561028b57fe5b049150600090505b60025481101561031d576001600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050151561031057600080fd5b8080600101915050610293565b7f9c26340b8d01b4e039192edfd25f4a56ed070d45afe866b8685658b1ed3cd74d34600254604051808381526020018281526020019250505060405180910390a1600192505050905600a165627a7a72305820f0e717ba935e00c43896cc9266a85af91a519061c044503be0a52b93f721d1610029' , gas: '4700000' }, function (e, contract){ console . log(e, contract); if (typeof contract . address !== 'undefined' ) { console . log( 'Contract mined! address: ' + contract . address + ' transactionHash: ' + contract . transactionHash); } })

We will see (almost immediately) that the contract is mined.

Now we can use the object revenuesharing to interact with this deployed contract.

Interacting with Deployed Contract

The deployed contract is accessed through the object revenuesharing.

1. Examine the public variables

We can examine those variables marked as “public”.

2. Execute the shareRevenue() function

Before we execute the shareRevenue() function, let’s take a look on the balance.

Note that some amount is deducted in accounts[0], who has deployed the contract. The amount of ether paid for the deployment is 417,626 weis. You can check it is the exact transaction cost when we did this in Remix.

Now we execute the function.

node console > revenuesharing . shareRevenue({from: web3 . eth . accounts[ 0 ], value: web3 . toWei( 30 ), gas: 4700000 });

Here we are calling the function shareRevenue(), and specifying that it is executed by accounts[0], with 30 ethers (toWei is a function in web3 is used to convert 30 ethers to wei, as wei is the unit accepted in the command). We also put the gas we allow to spend (It’s way more than required but we will get refund after execution).

After the transaction is executed, we can check the balance again.

We have achieved what we wish: 30 ethers are deducted from accounts[0] and distributed among accounts[1] to accounts[3] (now each of them has 110 ethers). Beside, some amount is paid for executing this transaction. It is 47,776 weis, again, matching what we observed in Remix.

Summary

We have successfully done the same thing on TestRPC. The overall flow is almost the same as that in Remix, except that we have to work on node console and web3 to interact with the blockchain in TestRPC. Next time we will do almost the same thing on a private Ethereum blockchain.

Author: KC TAM

KC began his blockchain journey just a few months ago. His interest is to dig out more detail “how things work”, and share with others what he has learnt.’LinkedIn: https://www. linkedin.com/in/ktam1/



