This is a series of blogs about how to develop dApps on Ethereum.

We developed a proof-of-concept example of lending platform on blockchain.
You can check live demo here.
* this is just a proof of concept example…

Last time we installed an Ethereum private network and IPFS node, if you’re interested in setting up an Ethereum private network, please check part 2. If you’re interested in client side implementation which includes light client and uPort please check part 1.

This time we’re going to cover topics like…

  • Smart contracts
  • Store and retrieve data on IPFS
  • Make transactions

Smart contract

Smart contract is a program which you can execute by sending transaction to the contract address. By using smart contract, we can develop almost any application on top of Ethereum blockchain network.

You can learn more here.

How to write contract

Because this is just an another programming language, you can use any editor to write codes. My favorite is Atom.

There are multiple choices to write codes for Ethereum blockchain. But here I use Solidity, which is similar to Javascript but you need to compile like C language.

How to deploy contract on blockchain

We have also multiple ways to compile Solidity codes. Most straight-forward way is just using solc command. But my favorite way is to use Remix. Remix is a web application to test solidity code online but you can also deploy your code even on your private network.

You can test your Solidity code on Javascript VM environment, which is default, to see if the code compile without errors. And change environment by choosing Web3 provider and put your RPC server address on it. This time your smart contract is going to be deployed on private blockchain.

Our loan platform contract

We have 2 contracts, LoancoinContract and LoancoinToken. LoancoinToken contract define token which user can lend and borrow. LoancoinContract contract define the status of loan contract.

Example : cerateLoanContract on loancoinContract contract.

First we don’t store contract detail on blockchain because of cost. Theoretically we can store any data on blockchain but storing data on blockchain means the data is copied on all blockchain nodes which can be million. And using disk spaces of million servers cost a lot. I bet you can image…

So we store loan contract detail on IPFS node and store only IPFS hash on blockchain.

This function take IPFS hash, borrower’s address, and lender’s address to create struct and save it and make the data accessible from the IPFS hash.

Here’s code snippet.

// struct
struct LoanContract {
  address lender;
  address borrower;
  string lender_sig;
  string borrower_sig;
  uint256 deadline; // -> deadline, 1513056825
  uint8 status;
  uint256 balance; // -> updated each month
  uint256 balanceUpdatedAt; // > to prevent double increase
// access to loan contract by mapping
mapping (string => LoanContract) private loanContracts;
// creat new laoncoin contract
function cerateLoanContract (
  string _ipfsHash,
  address _lender,
  address _borrower,
  uint256 _deadline
) public returns (bool success) {
  loanContracts[_ipfsHash] = LoanContract(
  return true;

Example: setLenderSig function on loancoinContract contract.

The setLenderSig function set lender’s signature.
Just retrieve contract data from IPFS hash and update status. After updating status, access to token contract to make it for borrower to withdraw token.

// set lenders signature
function setLenderSig (
  string _ipfsHash,
  string _lender_sig,
  address _token_addr,
  string _loanHash
) onlyOracle public returns (bool success) {
  LoanContract storage lc = loanContracts[_ipfsHash];
  if (lc.status != 0) revert();
  lc.lender_sig = _lender_sig;
  if ( bytes(lc.lender_sig).length != 0  &&     bytes(lc.borrower_sig).length != 0 && lc.status == 0 ) {
    // if there is no collateral, then revert
    uint256 _value = collateralOf(lc.lender, _loanHash);
    if ( _value == 0 ) revert();
    // we do not have collateral any more
    deleteCollateralOf(lc.lender, _loanHash);
    // allow
    lc.status = 1;
  return true;

Store and retrieve data on IPFS

I tried to save and get data on IPFS through node’s exec command first. It worked okay but once file size is getting big, cat command start showing error.

So I have decided to use IPFS node API. The API works great. All you have to do is making your string buffer.

// save encrypted data on ipfs. THIS IS OLD AND BAD VERSION
const exec = require('child_process').exec;
const save_data_on_ipfs = (_data) => {
return new Promise((resolve, reject) => {
    exec("echo "+_data+" | ipfs add -q", (err, results) => {
      if (err){
// save encrypted data on ipfs. BETTER VERSION
const ipfsAPI = require('ipfs-api')
const ipfs = ipfsAPI({host: 'localhost', port: '5001', protocol: 'http'})
const save_data_on_ipfs = (_data) => {
  return new Promise((resolve, reject) => {
    let ipfsHash
    return new Promise((resolve, reject) => {
      const _datax =  new Buffer(_data)
      ipfs.files.add( _datax,  (err, files) => {
        if (err) {
        } else {
          ipfsHash = files[0].hash

Make transaction on private blockchain network

Prepare contract instance

First you have to prepare so-called ABI file which is a json file of function definition. To create a ABI json file, LoancoinContract.json in this case, you can use truffle to compile contract.

Then get contract instance by putting the ABI file ( function definition ) and contract address you deployed to web3.eth.Contract method.

import LoancoinContractABI from './LoancoinContract.json'
let loanInstance = null
// prepare loan contarct instance
const prepareLoanContract =  ({ web3 }) => {
  return Promise.resolve()
  .then(() => {
    // get instance if needed
    if (loanInstance !== null){
      return Promise.resolve()
    return new web3.eth.Contract(LoancoinContractABI.abi, LOAN_ADDRESS)
  .then((results) => {
    // set instance if needed
    if (loanInstance !== null){
      return Promise.resolve()
    loanInstance = results
    return Promise.resolve()

Make transaction

To make transaction, you need to know how much gas you need to make the transaction. To do that, you can use estimateGas method.

Once you get gas cost, let’s send transaction to contract address by send method.

const deadline = (new Date().getTime() / 1000) + the_loan.duration * 30 * 24 * 60 * 60
// 1. you need to estimate gas
return loanInstance.methods.cerateLoanContract(
  from: <Address>
// 2. send transaction
return loanInstance.methods.cerateLoanContract(
  from: <Address>
  gasPrice: 100000000000,
  gas: estimateGas,

That’s it. you can see the data on blockchain with Remix.

Of course you need many more techniques and you need actual work, may be more work than normal we applications, to develop a real dApp. But I hope you can feel how it looks like to develop a dApp.


For lending platform we need to evaluate borrowers.
* We can not lend money to random anonymous people of course…

To be able to evaluate borrower’s credit worthiness, we need user identity, secure data sharing mechanism between lender and borrower and much more.

And because blockchain is too expensive for micro transactions, we need to implement a way to make transactions without paying fees or with extremely cheep fees.

One idea is Plasma which Vitalik Buterin and Joseph Poon proposed as scalability solution.

We’re going to implement Plamsa for Credit Hydra which is our project for user identity and secure data sharing platform on blockchain.

If you are interested in our project, please visit our website. and source code is here on github. Live demo is here.

Thanks for reading.

Also published on Medium.

Related posts:

Subscribe To Our Newsletter


You have Successfully Subscribed!

%d bloggers like this: