Skip to content

Module 6 – My First DApp with React (50 minutes)

herrerameri edited this page Dec 1, 2017 · 20 revisions

The idea is to create a simple DApp for parents.

They give some money to their children and wish that it can only be spent in some known and allowed places.

The smart contract

Take a look at the smart contract:

pragma solidity ^0.4.4;

contract ChildrenWallet {
  WalletAllowed[] public allowed;
  address parents;

  struct WalletAllowed {
    bytes32 name;
    address account;
  }
  
  function ChildrenWallet() {
    parents = msg.sender;
  }

  function addAllowed(bytes32 _name, address _account) returns (bool _success) {

    WalletAllowed memory newAllowed;
    newAllowed.name = _name;
    newAllowed.account = _account;

    allowed.push(newAllowed);
    return true;
  }

  function getAllowedNames() constant returns (bytes32[]) {    
      uint length = allowed.length;
      bytes32[] memory names = new bytes32[](length);

      for (uint i = 0; i < length; i++) {
          names[i] = allowed[i].name;
      }

      return names;
  }

  function getAllowedAddresses() constant returns (address[]) {    
      uint length = allowed.length;
      address[] memory addresses = new address[](length);

      for (uint i = 0; i < length; i++) {
          addresses[i] = allowed[i].account;
      }

      return addresses;
  }

  function buySomething(address _to) constant returns (string) {   
      uint length = allowed.length;
      for (uint i = 0; i < length; i++) {
          if (_to == allowed[i].account) {
            return "You can buy here";
          }
      } 
      return "You can not buy here";    
  }
}

It has some interesting parts. Let's analyze them:

  • The contract has 2 fields: an array of WalletAllowed, to save the places where the children can use their money; and an address called parents, to save the parents' address because later maybe we want to restrict some function for being used only for parents.
  • There's also one struct called WalletAllowed. It's like an object that represents an allowed place.
  • On the constructor function the parents' address is initialized (msg.sender is the address which creates the contract).

The functions are:

  • addAllowed: for the parents, to add an allowed place/wallet.
  • getAllowedNames: to get all the allowed names.
  • getAllowedAddresses: to get all the allowed addresses.
  • buySomething: to know if it's possible to buy on a place, with a given address.

So, let's start:

  1. On a console run testrpc
  2. Create a new project with Truffle as we did before with truffle init.
  3. Open the project with any code editor (Visual Studio Code, Atom or the one you have).
  4. Create a new contract and call it ChildrenWallet (truffle create contract ChildrenWallet).
  5. Copy and paste the Solidity code that is on top inside the ChildrenWallet.sol file.
  6. Migrate (deploy) the contracts to the blockchain with truffle migrate.
  7. Let's add a wallet with the commands:
var childrenContract;
var anAccount = web3.eth.accounts[0];

ChildrenWallet.deployed().then(function(instance){ childrenContract = instance; })
childrenContract.addAllowed('Library', anAccount).then(console.log)

Now, let's check the wallet was added:

childrenContract.getAllowedNames.call().then(console.log)

The result should be something similar to:

[ '0x4c69627261727900000000000000000000000000000000000000000000000000' ]

and that is good, because the type of the field 'name' of WalletAllowed is not a string, it's a bytes32[]. So, if you want to see the string you should try with the command:

 web3.toAscii('0x4c69627261727900000000000000000000000000000000000000000000000000')

We have the smart contract. To integrate the smart contract with our app, we'll need 2 things:

  • The contract address (you can get it with the command childrenContract.address)
  • The ABI (you can get it from the /build/contracts/ChildrenWallet.json file)

The following section will teach you how you can get a frontend that will show the smart contract information on a web site.

A frontend, with React.js

You'll need Node JS, version >= 6.

  1. Open a console and run:
npm install -g create-react-app

and:

create-react-app children-wallet

It will create a directory called children-wallet inside the current folder. 2) Open this directory with any code editor 3) We need web3, that's a library to interact with the smart contracts. We will also add lodash, a library that will help iterating arrays. Open the package.json file and modify the dependencies:

...
 "dependencies": {
    "react": "^16.1.1",
    "react-dom": "^16.1.1",
    "react-scripts": "1.0.17",
    "lodash": "^4.17.4",
    "web3": "^1.0.0-beta.24"
  }
...
  1. Now, type npm install in the console, to install these dependencies.
  2. We will write all our code in the App.js file, that's the main file in the app. Add the imports for the libraries on the top of the file:
import Web3 from 'web3';
import _ from 'lodash';
  1. Next to these lines, let's link the app to the smart contract we have deployed:
var client = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
var contractAbi = ABI;
var contractAddress = 'ADDRESS';
var contract = new client.eth.Contract(contractAbi, contractAddress); 

Replace ABI with your contract ABI, and ADDRESS with your contract address. Important! If you are not using testrpc, the port can be different (change it in http://localhost:8545)

  1. At this point, we have imported the libraries and we have a reference to the contract in the blockchain. Inside the App Component, copy and paste this code:
class App extends Component {
  constructor(props){
    super(props)
    this.state = {
      names: [],
      addresses: []
    }
  }
  componentWillMount(){
    contract.methods.getAllowedNames().call().then((promise) =>{      
      console.log(promise)
      this.setState({
          names : promise         
      });
    }); 
  
    contract.methods.getAllowedAddresses().call().then((promise) =>{      
      console.log(promise)
      this.setState({
          addresses : promise         
      });
    });      
  }

  render() {
    var tableRows = [];
    _.each(this.state.names, (value, index) => {
      tableRows.push(<tr>
                        <td>{client.utils.toAscii(this.state.names[index]).replace(/\u0000/g, '')}</td>
                        <td>{this.state.addresses[index]}</td>
                       </tr>
                      )          
    })
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to Children Wallet DAPP</h1>
        </header>
        <div className="App-Content">
          <table>
            <thead>
              <tr>
                <th>Names</th>
                <th>Addresses</th>
              </tr>
            </thead>
            <tbody> 
              {tableRows}
            </tbody>
          </table>
        </div>
      </div>
    );
  }
}

As you can see, there are calls to getAllowedAddresses and getAllowedNames, both are methods from the contract. In the render section, there's a variable, called tableRows where we are creating rows for a table to see the allowed names and addresses. You can run the code, typing npm start in the console.

The result is:

React1

It's our first DApp! :) 🥇 We have read data from the smart contract.

Now is your turn. Using the other methods (buySomething and addAllowed) you can interact with the smart contract. It'll be interesting if you use a field on the web site, where you can type the parameters and a button to call the smart contract.

Good luck!