Today we are going to write a complete de-centric (blockchain) application (Dapps), this article can be combined with the writing of smart contracts to see.
Write in front
Before reading this article, you should know something about Ethereum and smart contracts, and if you don't know it, it's recommended that you look at Ethereum first.
Besides, you'd better get some knowledge of HTML and JavaScript.
This article through the example teaches everybody to develop the central application, the application effect
From this article, you can learn to:
- Building an intelligent contract development environment
- Create a truffle project
- Write a smart contract
- Compiling and deploying smart contracts to blockchain
- How to interact with WEB3 and smart contracts
- Use of Metamask
Project background
Pete has a pet shop with 16 pets, and he wants to develop a hub-and-go app that lets people adopt pets.
In truffle box, the code for the Pet-shop site section has been provided, and we only need to write the contract and the interactive part.
Environment construction
- Install node
- Install Truffle:npm install -g truffle
- Installing ganache
The ganache (or ganache CLI) has replaced the TESTRPC.
Create a project
- Set up the project directory and enter
> mkdir pet-shop-tutorial> cd pet-shop-tutorial
- Create a project using truffle unbox
> truffle unbox pet-shopDownloading...Unpacking...Setting up...Unbox successful. Sweet!
Commands:
Compile:truffle Compile
Migrate:truffle Migrate
Test contracts:truffle Test
Run Dev server:npm Run dev
This step needs to wait for a while
> You can also use truffle init to create a completely new project.
## Project directory structure
`contracts /` folder of smart contracts, all smart contract files are placed here, which contains an important contract Migrations.sol (more on this later)
`migrations /` is used to handle deployment (migration) of smart contracts. Migration is an extra special contract to save contract changes.
`test /` smart contract test case folder
`truffle.js /` configuration file
Other codes can be ignored for the time being
## Writing smart contracts
Smart contracts are responsible for the background logic and storage of distributed applications. Smart contracts are written in solidity and can be read
[solidity series article] (https://learnblockchain.cn/categories/ethereum/Solidity/)
In the contracts directory, add the contract file Adoption.sol
`` `js
pragma solidity ^ 0.4.17;
contract Adoption {
address [16] public adopters; // save the address of the adopter
// Adopt a pet
function adopt (uint petId) public returns (uint) {
require (petId> = 0 && petId <= 15); // make sure the id is within the length of the array
adopters [petId] = msg.sender; // Save and call this address
return petId;
}
// return to adopter
function getAdopters () public view returns (address [16]) {
return adopters;
}
}
Compiling and deploying smart contracts
The 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 and requires that the readable solidity code be compiled into an EVM bytecode to run.
Dapp the root directory pet-shop-tutorial,
> truffle compile
Output
Compiling ./contracts/Adoption.sol...Writing artifacts to ./build/contracts
Deployment
Once compiled, it can be deployed to the blockchain.
There is already a 1_initial_migration.js deployment script under the Migrations folder to deploy the Migrations.sol contract.
Migrations.sol is used to ensure that the same contract is 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 you perform the deployment, you need to ensure that a blockchain is running and you can use
Ganache to open a private chain for development testing, the default is to run a development chain on port 7545.
This is the case when ganache is started:
Next, execute the deployment 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 changes in the blockchain state, which now produces 4 blocks.
This means that the smart contract has been deployed.
Test
Now let's test the smart contract, the test case can be written in JavaScript or solidity, where solidity is used.
testcreate a new one in the directoryTestAdoption.sol, write a test contract
pragma solidity ^ 0.4.17;
import "truffle / Assert.sol"; // Assertion introduced
import "truffle / DeployedAddresses.sol"; // used to get the addresses of the tested contracts
import "../contracts/Adoption.sol"; // contract tested
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 {
// The address of the expected 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 do not provide a truffle directory under the test directory.
Add adopt test Cases to the Testadoption contract
Run test Cases
In the terminal, perform the
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 interactions
We have written and deployed and tested our contracts, and then we write the UI for the contract so that the contracts can actually be used.
In truffle boxpet-shop, the front-end code for the app is included, and the code is in thesrc/folder.
Open in Editorsrc/js/app.js
You can see the app object used to manage the entire app, and the init function loads the pet information and initializes the WEB3.
WEB3 is a library that implements communication with the Ethereum node, and we use WEB3 to interact with the contract.
Initialize WEB3
Next, let's edit app.js to modify the 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 takes precedence over the WEB3 instance provided by mist or metamask, and if not, creates one from the local environment.
Instantiate a contract
Using Truffle-contract will help us save the contract deployment information, we do not need to manually modify the contract address, modify the Initcontract () code as follows:
initContract: function () {
// Load Adoption.json, save the ABI (Interface Description) information of Adoption and the deployed network (address) information. It generates ABI when compiling the contract, and adds network information when deploying
$ .getJSON (‘Adoption.json’, function (data) {
// Create an interactive TruffleContract contract 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 adoptions
Modify the markadopted () code:
markAdopted: function (adopters, account) {
var adoptionInstance;
App.contracts.Adoption.deployed (). Then (function (instance) {
adoptionInstance = instance;
// Call the contract's getAdopters (), read the information with call 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 the Handleadopt () code:
handleAdopt: function (event) {
event.preventDefault ();
var petId = parseInt ($ (event.target) .data (‘id‘));
var 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 a transaction to adopt a pet
return adoptionInstance.adopt (petId, (from: account));
}). then (function (result) {
return App.markAdopted ();
}). catch (function (err) {
console.log (err.message);
});
});
}
Run the installation metamask in the browser
Metamask is a plug-in form of the Ethereum light client, the development process using Metamask and our Dapp to interact is a good choice, through this link installation, after installation, the browser toolbar will display a small Fox icon.
Configure Wallets
After accepting the privacy statement, the following page appears:
Here we create a good wallet for us by restoring a ganache as our development test wallet. Click Import Existing DENin the page to enter the mnemonic words ganache display.
candy maple cake sugar pudding cream honey rich smooth crumble sweet treat
Then you want the password, click OK.
Connecting the block chain network of development zone
The default connection is the Ethereum main network (upper left corner display), select Custom RPC, add a network:http://127.0.0.1:7545, after the point is returned, the following is displayed:
This is shown in the upper left corner as Private Network, the account is the default first account in ganache.
As of this metamask installation, the configuration is complete.
Installing and configuring Lite-server
Next requires a local Web server to provide access to the service, truffle box pet-shop provides a lite-server that can be used directly, and we'll see how it works.
Bs-config.json indicates the working directory of the Lite-server.
{ "server": { "baseDir": ["./src", "./build/contracts"] }}
./SRC is the Web site file directory
./build/contracts is the contract output directory
At the same time, the dev command is added to the scripts of the Package.json file:
"scripts": { "dev": "lite-server", "test": "echo \"Error: no test specified\" && exit 1"},
When running NPM run Dev, the Lite-server is started
Start the service
> npm run dev
will automatically open the browser to display our Dapp, such as the first picture of this article.
Now adoption has been pet look, when we click adopt , Metamask will prompt us to confirm the transaction,
After clicking on the submit confirmation, you can see that the pet was adopted successfully.
In Metamask, you can also see a list of transactions:
Well, congratulations, you've become a solid step towards becoming a hub-and-go application developer.
Reference documents
In-depth blockchain-the system learns blockchain to create the best blockchain technology blog.
Step by step to teach you to develop and deploy your first de-centralized application (Dapp)-Pet Shop