Вы находитесь на странице: 1из 9

Workshop Handbook

A. Preparing for development

1. Install a code editor of your choice


 For workshop purpose, facilitator will use https://code.visualstudio.com/
2. Install a bash command line terminal of your choice
 For workshop purpose, facilitator will use http://cmder.net/
3. Install Node.js and Node Package Manager (npm)
 https://www.npmjs.com/get-npm
4. Install geth
 https://geth.ethereum.org/downloads/
5. Install Google Chrome
 https://www.google.com/chrome/
6. Install Metamask
 https://metamask.io/
7. Install Mist browser (optional)
 https://github.com/ethereum/mist/releases

B. MyEtherWallet

1. Open web browser


2. Go to https://myetherwallet.com
3. Create a new wallet (use a password for security)
4. Save UTC/JSON keystore file (download) into your PC

C. Ganache or Ganache CLI (formerly TestRPC)

1. Install Ganache from the installer


2. For ganache CLI, open bash terminal
3. Install Ganache CLI from NPM
npm install -g ganache-cli

4. Run Ganache CLI


ganache-cli
D. Geth

1. Make sure you have installed the latest version of geth


2. To start a development version of geth, use geth --dev
3. Optional: directly connect to console using geth --dev console
4. To connect to an existing connection, e.g. from TestRPC, use geth attach http://localhost:7545

E. Basic Web3 Javascript Console Commands

1. Make sure you have connected to the geth console using either console or attach command
2. To check balance, use web3.eth.getBalance(address)
3. To send a transaction, use web3.eth.sendTransaction(txObject)
4. Basic conversion from wei to ether: web3.fromWei(weiValue)
5. Specification of a transaction object that we can use in the above command:
 from: String - The address for the sending account. Uses the web3.eth.defaultAccount
property, if not specified.
 to: String - (optional) The destination address of the message, left undefined for a contract-
creation transaction.
 value: Number|String|BigNumber - (optional) The value transferred for the transaction in
Wei, also the endowment if it's a contract-creation transaction.
 gas: Number|String|BigNumber - (optional, default: To-Be-Determined) The amount of gas
to use for the transaction (unused gas is refunded).
 gasPrice: Number|String|BigNumber - (optional, default: To-Be-Determined) The price of
gas for this transaction in wei, defaults to the mean network gas price.
 data: String - (optional) Either a byte string containing the associated data of the message,
or in the case of a contract-creation transaction, the initialisation code.
 nonce: Number - (optional) Integer of a nonce. This allows to overwrite your own pending
transactions that use the same nonce.
6. For example, this object is valid for a transaction:
var txObject = { from: address, to: address, value: ethervalue }

F. Metamask

1. Use Google Chrome browser/Brave browser


2. Go to https://metamask.io
3. Download Metamask Google Chrome extension (if using Chrome)
4. Accept Terms and Conditions
5. Set password
6. Start using Metamask
7. Optional: Change network to Ropsten or testrpc

G. Interacting with TestRPC using Metamask

1. Open web browser


2. Go to https://myetherwallet.com
3. Create a new wallet
4. Save UTC/JSON keystore file (download) into your PC
5. Test sending and receiving Ether using Metamask

H. Etherscan

1. Go to https://ropsten.etherscan.io
2. Input an address to find out information about it

I. Truffle Framework preparation

1. Run npm install -g truffle


2. Make a working directory for Truffle project and go inside the folder
 Example: "C:\Workshop\task1"
3. Run truffle init
4. Open code editor in the working directory
 Visual studio code command: code .
 Atom command: atom .

J. Truffle Framework Hello World

1. Make a working directory for Truffle project and go inside the folder
 Example: "C:\Workshop\helloworld"
2. Run truffle init
3. Open code editor in the working directory
 Visual studio code command: code .
 Atom command: atom .
4. Directory structure

The default Truffle directory structure contains the following:


contracts/: Contains the Solidity source files for our smart contracts. There is an important contract
in here called Migrations.sol, which we'll talk about later.
migrations/: Truffle uses a migration system to handle smart contract deployments. A migration is
an additional special smart contract that keeps track of changes.
test/: Contains both JavaScript and Solidity tests for our smart contracts
truffle-config.js: Truffle configuration file

5. In folder "contracts", create a new file named "HelloWorld.sol"


6. Copy the following code inside the newly created "HelloWorld.sol" file
pragma solidity ^0.5.8;

contract HelloWorld {
string public message;

constructor() public {
message = "Hello World";
}

function setMessage(string memory _message) public {


message = _message;
}
}

The minimum version of Solidity required is noted at the top of the contract: pragma solidity ^0.5.8;.
The pragma command means "additional information that only the compiler cares about", while the
caret symbol (^) means "the version indicated or higher".
Like JavaScript or PHP, statements are terminated with semicolons.

7. Create a file inside folder "migrations" called "2_deploy_contracts.js" and set the value into this

var HelloWorld = artifacts.require("./HelloWorld.sol");

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

8. Change the content of truffle.js (and truffle-config.js) into this


module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 7545,
network_id: "*" // Match any network id
}
}
};

9. On your bash terminal, run truffle compile to compile your code


10. With a running RPC client, run truffle migrate to deploy your contract into the network
11. To interact with your contract, run truffle console to get into the console
12. Run this command to get your contract instance:
HelloWorld.deployed().then(function(instance){contract=instance})
13. Get the first private key and set it in the account from your local ethereum keystore
var account = web3.eth.accounts.privateKeyToAccount(‘0xprivkey’);

14. Get the first account's amount of ether owned


web3.eth.getBalance(account.address);
15. Call the contract public message variable
contract.message.call();
16. Set the contract message by sending a transaction to the setMessage function
contract.setMessage.sendTransaction("New message",{from:account.address})
17. If the transaction has been mined, you will receive a transaction hash. Verify it using this command
web3.eth.getTransaction('0xd83dddd8b3be9466ff6239a39f3bcc36f506c760f7702e9e740949b9fa60e834')
18. Verify that the account's ether is reduced to pay for the gas
web3.eth.getBalance(account.address);
19. Call the contract public variable again and make sure the message has been updated
contract.message.call();

K. Truffle Boxes & Pet Shop Tutorial (Part I: Smart Contract)

1. Browse to https://www.trufflesuite.com/boxes
2. Select pet-shop
3. Unbox the truffle box using this command: truffle unbox pet-shop
4. In folder "contracts", create a new file named "Adoption.sol"
5. Copy the following code inside the newly created "Adoption.sol" file
pragma solidity ^0.5.0;

contract Adoption {
address[16] public adopters;

// Adopting a pet
function adopt(uint petId) public returns (uint) {
require(petId >= 0 && petId <= 15);

adopters[petId] = msg.sender;

return petId;
}

// Retrieving the adopters


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

 We've defined a single variable: adopters. This is an array of Ethereum addresses. Arrays
contain one type and can have a fixed or variable length. In this case the type is address and
the length is 16.
 You'll also notice adopters is public. Public variables have automatic getter methods, but in
the case of arrays a key is required and will only return a single value. Later, we'll write a
function to return the whole array for use in our UI.
 In Solidity the types of both the function parameters and output must be specified. In this
case we'll be taking in a petId (integer) and returning an integer.
 We are checking to make sure petId is in range of our adopters array. Arrays in Solidity are
indexed from 0, so the ID value will need to be between 0 and 15. We use the require()
statement to ensure the ID is within range.
 If the ID is in range, we then add the address that made the call to our adopters array. The
address of the person or smart contract who called this function is denoted by msg.sender.
 Finally, we return the petId provided as a confirmation.
 Since adopters is already declared, we can simply return it. Be sure to specify the return type
(in this case, the type for adopters) as address[16] memory. memory gives the data location
for the variable.
 The view keyword in the function declaration means that the function will not modify the
state of the contract.

6. Create a file inside folder "migrations" called "2_deploy_contracts.js" and set the value into this

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

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

7. On your bash terminal, run truffle compile to compile your code


8. With a running RPC client, run truffle migrate to deploy your contract into the network
L. Truffle Boxes & Pet Shop Tutorial (Part II: User Interface)

1. Open the pet-shop Truffle project you have previously created


2. Open /src/js/app.js in a text editor.
3. Examine the file. Note that there is a global App object to manage our application, load in the pet
data in init() and then call the function initWeb3(). The web3 JavaScript library interacts with the
Ethereum blockchain. It can retrieve user accounts, send transactions, interact with smart
contracts, and more.
4. Remove the multi-line comment from within initWeb3 and replace it with the following:

// Modern dapp browsers...


if (window.ethereum) {
App.web3Provider = window.ethereum;
try {
// Request account access
await window.ethereum.enable();
} catch (error) {
// User denied account access...
console.error("User denied account access")
}
}
// Legacy dapp browsers...
else if (window.web3) {
App.web3Provider = window.web3.currentProvider;
}
// If no injected web3 instance is detected, fall back to Ganache
else {
App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
}
web3 = new Web3(App.web3Provider);

5. Now that we can interact with Ethereum via web3, we need to instantiate our smart contract so
web3 knows where to find it and how it works. Truffle has a library to help with this called truffle-
contract. It keeps information about the contract in sync with migrations, so you don't need to
change the contract's deployed address manually. Still in /src/js/app.js, remove the multi-line
comment from within initContract and replace it with the following:

$.getJSON('Adoption.json', function(data) {
// Get the necessary contract artifact file and instantiate it with truffle-contract
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();
});

 We first retrieve the artifact file for our smart contract. Artifacts are information about our
contract such as its deployed address and Application Binary Interface (ABI). The ABI is a
JavaScript object defining how to interact with the contract including its variables, functions
and their parameters.
 Once we have the artifacts in our callback, we pass them to TruffleContract(). This creates
an instance of the contract we can interact with.
 With our contract instantiated, we set its web3 provider using the App.web3Provider value
we stored earlier when setting up web3.
 We then call the app's markAdopted() function in case any pets are already adopted from a
previous visit. We've encapsulated this in a separate function since we'll need to update the
UI any time we make a change to the smart contract's data.

6. Still in /src/js/app.js, remove the multi-line comment from markAdopted and replace it with the
following:

var adoptionInstance;

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

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);
});

 We access the deployed Adoption contract, then call getAdopters() on that instance.
 We first declare the variable adoptionInstance outside of the smart contract calls so we can
access the instance after initially retrieving it.
 Using call() allows us to read data from the blockchain without having to send a full
transaction, meaning we won't have to spend any ether.
 After calling getAdopters(), we then loop through all of them, checking to see if an address
is stored for each pet. Since the array contains address types, Ethereum initializes the array
with 16 empty addresses. This is why we check for an empty address string rather than null
or other falsey value.
 Once a petId with a corresponding address is found, we disable its adopt button and change
the button text to "Success", so the user gets some feedback.
 Any errors are logged to the console.

7. Still in /src/js/app.js, remove the multi-line comment from handleAdopt and replace it with the
following:

var adoptionInstance;

web3.eth.getAccounts(function(error, accounts) {
if (error) {
console.log(error);
}

var account = accounts[0];


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

// Execute adopt as a transaction by sending account


return adoptionInstance.adopt(petId, {from: account});
}).then(function(result) {
return App.markAdopted();
}).catch(function(err) {
console.log(err.message);
});
});

8. We can now start a local web server and use the dapp. We're using the lite-server library to serve
our static files. This shipped with the pet-shop Truffle Box, but let's take a look at how it works.

Open bs-config.json in a text editor (in the project's root directory) and examine the contents:
{

"server": {

"baseDir": ["./src", "./build/contracts"]

This tells lite-server which files to include in our base directory. We add the ./src directory for our
website files and ./build/contracts directory for the contract artifacts.

We've also added a dev command to the scripts object in the package.json file in the project's root
directory. The scripts object allows us to alias console commands to a single npm command. In this case
we're just doing a single command, but it's possible to have more complex configurations. Here's what
yours should look like:
"scripts": {

"dev": "lite-server",

"test": "echo \"Error: no test specified\" && exit 1"

},

This tells npm to run our local install of lite-server when we execute npm run dev from the console.

Вам также может понравиться