Teach you to develop and deploy your first decentralized application (Dapp) step by step - Pet Store

Today we are going to write a complete decentralized (blockchain) application (Dapps). This article can be combined with writing smart contracts .

write in front

Before reading this article, you should have some understanding of Ethereum and smart contracts. If you don’t know it yet, I suggest you read what Ethereum is.
In addition, you’d better have some knowledge of HTML and JavaScript.

This article teaches you to develop decentralized applications through examples. The application effect is as follows:

From this article, you can learn:

  • Build a smart contract development environment
  • Create a Truffle project
  • Write smart contracts
  • Compile and deploy smart contracts to the blockchain
  • How to interact with smart contracts via Web3
  • Use of MetaMask

Small column users can download the complete Dapp code at the end of the tutorial.

Background of the project

Pete has a pet store with 16 pets, and he wants to develop a decentralized application for people to adopt pets.
In the truffle box, the code of the website part of the pet-shop has been provided, we only need to write the contract and interaction part.

Environment construction

  1. Install Node
  2. Install Truffle:npm install -g truffle
  3. Install Ganache

Ganache (or Ganache CLI) has replaced testrpc.

Create project

    1. Create a project directory and enter

> mkdir pet-shop-tutorial
> cd pet-shop-tutorial

    2. Use truffle unbox to create a project

> truffle unbox pet-shop
 Downloading...
 Unpacking...
 Setting up...
 Unbox successful. Sweet!

Commands:

  Compile:        truffle compile
  Migrate:        truffle migrate
  Test contracts: truffle test
  Run dev server: npm run dev

 

You can also use truffle init to create a completely new project.

Project directory structure

contracts/ The smart contract folder, where all smart contract files are placed, contains an important contract, Migrations.sol (more on this later)
migrations/ that handles deploying (migrating) smart contracts, migrations are an extra special contract for Save contract changes.
test/ Smart Contract Test Case Folder
truffle.js/ Configuration File

Other codes can be ignored temporarily

Write smart contracts

Smart contracts are responsible for the background logic and storage of distributed applications. Smart contracts are written in solidity, you can read
the solidity series of articles

In the contracts directory, add the contract file Adoption.sol

pragma solidity ^ 0.4.17;

contract Adoption {

  address[16] public adopters; // Save the address of adopters

    // Adopt a pet
  function adopt(uint petId) public returns (uint) {
    require(petId >= 0 && petId <= 15); // make sure the id is within the array length

    adopters[petId] = msg.sender; // save the calling address
    return petId;
  }

  // return the adopter
  function getAdopters() public view returns (address[16]) {
    return adopters;
  }

}

Compile and deploy smart contracts

Truffle integrates a developer console that can be used to generate a development chain for testing and deploying smart contracts.

compile

Solidity is a compiled language, which requires readable Solidity code to be compiled into EVM bytecode to run.
Under the root directory pet-shop-tutorial of dapp,

> truffle compile

output

Compiling ./contracts/Adoption.sol...
Writing artifacts to ./build/contracts

deploy

Once compiled, it can be deployed to the blockchain.
There is already a 1_initial_migration.js deployment script in the migrations folder to deploy the Migrations.sol contract.
Migrations.sol is used to ensure that the same contracts are not deployed.

Now let's create a deployment script of our own2_deploy_contracts.js

var Adoption = artifacts.require("Adoption");

module.exports = function(deployer) {
  deployer.deploy(Adoption);
};

Before executing the deployment, you need to ensure that there is a blockchain running. You can use
Ganache to open a private chain for development and testing. By default, a development chain will run on port 7545.
This is what Ganache looks like after it starts:

Next execute the deploy command:

truffle  migrate

After execution, there is a similar output,

Using network 'develop'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0x3076b7dac65afc44ec51508bf6f2b6894f833f0f9560ecad2d6d41ed98a4679f
  Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
  ... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying Adoption...
  ... 0x2c6ab4471c225b5473f2079ee42ca1356007e51d5bb57eb80bfeb406acc35cd4
  Adoption: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
  ... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts...

In the open Ganache, you can see the changes in the state of the blockchain, and now 4 blocks have been generated. At this point, the smart contract has been deployed.

test

Now let's test the smart contract, the test cases can be written in JavaScript or Solidity, here we use Solidity.

Create a new one in the testdirectory TestAdoption.soland write a test contract

pragma solidity ^ 0.4.17;

import "truffle/Assert.sol"; // Assertions introduced
import "truffle/DeployedAddresses.sol"; // used to get the address of the tested contract
import "../contracts/Adoption.sol"; // contract under test

contract TestAdoption {
  Adoption adoption = Adoption(DeployedAddresses.Adoption());

  // Adoption test case
  function testUserCanAdoptPet() public {
    uint returnedId = adoption.adopt(8);

    uint expected = 8;
    Assert.equal(returnedId, expected, "Adoption of pet ID 8 should be recorded.");
  }

  // pet owner test case
  function testGetAdopterAddressByPetId() public {
    // It is expected that the address of the adopter is the address of this contract, because the transaction is initiated by the test contract,
    address expected = this;
    address adopter = adoption.adopters(8);
    Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded.");
  }

    // Test all adopters
  function testGetAdopterAddressByPetIdInArray() public {
  // The address of the adopter is the address of this contract
    address expected = this;
    address[16] memory adopters = adoption.getAdopters();
    Assert.equal(adopters[8], expected, "Owner of pet ID 8 should be recorded.");
  }
}

Assert.sol and DeployedAddresses.sol are provided by the Truffle framework, and the truffle directory is not provided in the test directory.

Add the test case for adopt in the TestAdoption contract

run test cases

In a terminal, execute

truffle test

If the test passes, the terminal outputs:

Using network 'develop'.

Compiling ./contracts/Adoption.sol...
Compiling ./test/TestAdoption.sol...
Compiling truffle/Assert.sol...
Compiling truffle/DeployedAddresses.sol...


  TestAdoption
    ✓ testUserCanAdoptPet (62ms)
    ✓ testGetAdopterAddressByPetId (53ms)
    ✓ testGetAdopterAddressByPetIdInArray (73ms)


  3 passing (554ms)

Create user interface and smart contract interaction

Now that we have written, deployed and tested our contract, let's write the UI for the contract so that the contract can actually be used.

In the Truffle Box  pet-shop, the front-end code of the application has been included, and the code is under the src/folder.

Open in the editor and you src/js/app.js
can see the App object used to manage the entire application. The init function loads the pet information and initializes web3 .
Web3 is a library that implements communication with Ethereum nodes. We use web3 to interact with contracts.

initialize web3

Next, let's edit app.js and modify initWeb3():
delete the comment and modify it to:

initWeb3: function() {
  // Is there an injected web3 instance?
  if (typeof web3 !== 'undefined') {
    App.web3Provider = web3.currentProvider;
  } else {
    // If no injected web3 instance is detected, fall back to Ganache
    App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
  }
  web3 = new Web3(App.web3Provider);

  return App.initContract();
}

The code prefers to use the web3 instance provided by Mist  or  MetaMask , if not, create one from the local environment.

instantiate the contract

Using truffle-contract will help us save the contract deployment information, so we don't need to manually modify the contract address. Modify the initContract() code as follows:

initContract: function() {
  // Load Adoption.json, which saves Adoption's ABI (interface description) information and deployed network (address) information. It generates ABI when compiling the contract, and appends network information when deploying
  $.getJSON('Adoption.json', function(data) {
    // Create an interactive TruffleContract instance with Adoption.json data.
    var AdoptionArtifact = data;
    App.contracts.Adoption = TruffleContract(AdoptionArtifact);

    // Set the provider for our contract
    App.contracts.Adoption.setProvider(App.web3Provider);

    // Use our contract to retrieve and mark the adopted pets
    return App.markAdopted();
  });
  return App.bindEvents();
}

Handling adoption

Modify the markAdopted() code:

markAdopted: function(adopters, account) {
  was adoptionInstance;

  App.contracts.Adoption.deployed().then(function(instance) {
    adoptionInstance = instance;

    // Call getAdopters() of the contract, use call to read information without consuming gas
    return adoptionInstance.getAdopters.call();
  }).then(function(adopters) {
    for (i = 0; i < adopters.length; i++) {
      if (adopters[i] !== '0x0000000000000000000000000000000000000000') {
        $('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true);
      }
    }
  }).catch(function(err) {
    console.log(err.message);
  });
}

Modify handleAdopt() code:

handleAdopt: function(event) {
  event.preventDefault();

  var petId = parseInt($(event.target).data('id'));

  was adoptionInstance;

  // get user account
  web3.eth.getAccounts(function(error, accounts) {
    if (error) {
      console.log(error);
    }
  
    var account = accounts[0];
  
    App.contracts.Adoption.deployed().then(function(instance) {
      adoptionInstance = instance;
  
      // Send transaction to adopt pet
      return adoptionInstance.adopt(petId, {from: account});
    }).then(function(result) {
      return App.markAdopted();
    }).catch(function(err) {
      console.log(err.message);
    });
  });
}

run in browser

Install MetaMask

MetaMask is an Ethereum light client in the form of a plug-in. It is a good choice to use MetaMask to interact with our dapp during the development process. Install it through this link . After the installation is complete, a small fox icon will be displayed on the browser toolbar.

Configure wallet

After accepting the privacy statement, the following page will appear:

Here we restore a wallet created for us by Ganache as our development and test wallet. Click  Import Existing DEN on the page and enter the mnemonic displayed by Ganache.

spoon chief pass thunder any eagle force rally body annual roof trip

Then the desired password, click OK.
As shown in the figure:

Connect to develop a blockchain network

The default connection is the Ethereum main network (displayed in the upper left corner), select Custom RPC , add a network: http://127.0.0.1:7545 , after clicking back, the display is as follows: This is the upper left corner displayed as Private Network , and the account is Ganache The default first account in .

So far, the installation and configuration of MetaMask has been completed.

Install and configure lite-server

Next, a local web server is required to provide service access.  A lite-server is provided in the Truffle Box pet-shop that can be used directly. Let's see how it works. bs-config.json indicates the working directory of lite-server.

{
  "server": {
    "baseDir": ["./src", "./build/contracts"]
  }
}

./src is the website file directory

./build/contracts is the contract output directory

At the same time, the dev command was added to the scripts in the package.json file:

"scripts": {
  "dev": "lite-server",
  "test": "echo \"Error: no test specified\" && exit 1"
},

When running npm run dev, it will start lite-server

start the service

> npm run dev

The browser will automatically open to display our dapp, as shown in the first picture in this article.
Now we have adopted a pet and have a look. When we click on Adopt , MetaMask will prompt us to confirm the transaction, as shown in the figure:

After clicking Submit to confirm, you can see that the pet has been adopted successfully.

In MetaMask, the list of transactions can also be seen:

Well, congratulations, you have taken a solid step towards becoming a decentralized application developer.
If you encounter problems in learning, please come to my knowledge planet to exchange.

Reference documentation

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325343137&siteId=291194637