【Ethereum】ECR20を発行しよう

$ pip3 install eth-brownie
$ npm install -g ganache-cli
$ brownie init
$ tree
.
├── build
│ ├── contracts
│ ├── deployments
│ └── interfaces
├── contracts
├── interfaces
├── reports
├── scripts
└── tests

contract/TokenERC20.sol
https://github.com/PatrickAlphaC/erc20-brownie/tree/main/contracts

pragma solidity ^0.6.0;

interface tokenRecipient { 
    function receiveApproval(address _from, uint256 _value, address _token, bytes calldata _extraData) external; 
}

contract TokenERC20 {
    // Public variables of the token
    string public name;
    string public symbol;
    uint8 public decimals = 18;
    // 18 decimals is the strongly suggested default, avoid changing it
    uint256 public totalSupply;

    // This creates an array with all balances
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;

    // This generates a public event on the blockchain that will notify clients
    event Transfer(address indexed from, address indexed to, uint256 value);
    
    // This generates a public event on the blockchain that will notify clients
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);

    // This notifies clients about the amount burnt
    event Burn(address indexed from, uint256 value);

    /**
     * Constructor function
     *
     * Initializes contract with initial supply tokens to the creator of the contract
     */
    constructor(
        uint256 initialSupply,
        string memory tokenName,
        string memory tokenSymbol
    ) public {
        totalSupply = initialSupply * 10 ** uint256(decimals);  // Update total supply with the decimal amount
        balanceOf[msg.sender] = totalSupply;                // Give the creator all initial tokens
        name = tokenName;                                   // Set the name for display purposes
        symbol = tokenSymbol;                               // Set the symbol for display purposes
        emit Transfer(address(0), msg.sender, totalSupply);

    }

    /**
     * Internal transfer, only can be called by this contract
     */
    function _transfer(address _from, address _to, uint _value) internal {
        // Prevent transfer to 0x0 address. Use burn() instead
        require(_to != address(0x0));
        // Check if the sender has enough
        require(balanceOf[_from] >= _value);
        // Check for overflows
        require(balanceOf[_to] + _value >= balanceOf[_to]);
        // Save this for an assertion in the future
        uint previousBalances = balanceOf[_from] + balanceOf[_to];
        // Subtract from the sender
        balanceOf[_from] -= _value;
        // Add the same to the recipient
        balanceOf[_to] += _value;
        emit Transfer(_from, _to, _value);
        // Asserts are used to use static analysis to find bugs in your code. They should never fail
        assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
    }

    /**
     * Transfer tokens
     *
     * Send `_value` tokens to `_to` from your account
     *
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transfer(address _to, uint256 _value) public returns (bool success) {
        _transfer(msg.sender, _to, _value);
        return true;
    }

    /**
     * Transfer tokens from other address
     *
     * Send `_value` tokens to `_to` on behalf of `_from`
     *
     * @param _from The address of the sender
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(_value <= allowance[_from][msg.sender]);     // Check allowance
        allowance[_from][msg.sender] -= _value;
        _transfer(_from, _to, _value);
        return true;
    }

    /**
     * Set allowance for other address
     *
     * Allows `_spender` to spend no more than `_value` tokens on your behalf
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     */
    function approve(address _spender, uint256 _value) public
        returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    /**
     * Set allowance for other address and notify
     *
     * Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     * @param _extraData some extra information to send to the approved contract
     */
    function approveAndCall(address _spender, uint256 _value, bytes memory _extraData)
        public
        returns (bool success) {
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            spender.receiveApproval(msg.sender, _value, address(this), _extraData);
            return true;
        }
    }

    /**
     * Destroy tokens
     *
     * Remove `_value` tokens from the system irreversibly
     *
     * @param _value the amount of money to burn
     */
    function burn(uint256 _value) public returns (bool success) {
        require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough
        balanceOf[msg.sender] -= _value;            // Subtract from the sender
        totalSupply -= _value;                      // Updates totalSupply
        emit Burn(msg.sender, _value);
        return true;
    }

    /**
     * Destroy tokens from other account
     *
     * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
     *
     * @param _from the address of the sender
     * @param _value the amount of money to burn
     */
    function burnFrom(address _from, uint256 _value) public returns (bool success) {
        require(balanceOf[_from] >= _value);                // Check if the targeted balance is enough
        require(_value <= allowance[_from][msg.sender]);    // Check allowance
        balanceOf[_from] -= _value;                         // Subtract from the targeted balance
        allowance[_from][msg.sender] -= _value;             // Subtract from the sender's allowance
        totalSupply -= _value;                              // Update totalSupply
        emit Burn(_from, _value);
        return true;
    }
}

$ brownie compile
$ ganache-cli
Ganache CLI v6.12.2 (ganache-core: 2.13.2)
(node:179457) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node –trace-deprecation …` to show where the warning was created)

Available Accounts
==================
(0) 0xe866BE96aA793C69dc4CB69D717D12e7b0d5267d (100 ETH)
(1) 0x0696f9fB2fFe037F6E13Deba40912562f97faDC2 (100 ETH)
(2) 0x3785c546Fe6Fc72a7468059d4f7eE6f3d4727F2C (100 ETH)
(3) 0x11165cCc75b3E917C9918C529778c9cE4E58d513 (100 ETH)
(4) 0x3B26Bfe04381231728b9ca3bbC42435aa6D2155e (100 ETH)
(5) 0x9aA0b1bd92d42Da1cA1e842A05Ec5c69F3Dcd123 (100 ETH)
(6) 0x0aC021eCA14d61880693fd6Cd0FAAD598f208778 (100 ETH)
(7) 0xbd07f6ad435698D878f94D9A29337E09c51fd900 (100 ETH)
(8) 0xb8d7f305778207E48A1b70D1D54226ABd76156De (100 ETH)
(9) 0x7e41f77B97d567178A1443E2fe44d3168111BaF6 (100 ETH)

Private Keys
==================
// 省略

HD Wallet
==================
Mnemonic: course acid cereal genuine old blind someone ticket thrive palace napkin time
Base HD Path: m/44’/60’/0’/0/{account_index}

Gas Price
==================
20000000000

Gas Limit
==================
6721975

Call Gas Limit
==================
9007199254740991

Listening on 127.0.0.1:8545

script/deploy_token.py

from brownie import accounts, config, TokenERC20

initial_supply = 1000000000000000000000  # 1000
token_name = "Hpscript"
token_symbol = "HPS"

def main():
    account = accounts.add(config["wallets"]["from_key"])
    erc20 = TokenERC20.deploy(
        initial_supply, token_name, token_symbol, {"from": account} , publish_source=True 
    )

brownie-config.yaml

dependencies:
  - OpenZeppelin/openzeppelin-contracts@3.4.0
compiler:
  solc:
    remappings:
      - '@openzeppelin=OpenZeppelin/openzeppelin-contracts@3.4.0'
dotenv: .env
wallets:
  from_key: ${PRIVATE_KEY}

.env

export WEB3_INFURA_PROJECT_ID=''
export PRIVATE_KEY=''
export ETHERSCAN_TOKEN=''

$ source .env
$ brownie run scripts/deploy_token.py –network sepolia

スマートコントラクトで作るのか… なるほどね〜

[Ethereum] SolidityのContractをweb3.jsで呼び出したい

<body>
  <script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"></script>
	<script>
    const web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io/v3/*"));
      const address = "*";
      const abi = [{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"clients","outputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"gender","type":"string"},{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_gender","type":"string"},{"internalType":"uint256","name":"_weight","type":"uint256"},{"internalType":"uint256","name":"_height","type":"uint256"}],"name":"register","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"excesise","outputs":[{"internalType":"uint256","name":"newWeight","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]

      const contract = new web3.eth.Contract(abi, address);
      const handleCall = async () => {
        await contract.methods.register("tanaka", "aaa", 65, 175);
        const result = await contract.methods.excesise.call();
        console.log(result);
      };
      handleCall();
      
    </script>
</body>
</html>

{arguments: Array(0), call: ƒ, send: ƒ, encodeABI: ƒ, estimateGas: ƒ, …}

何故だろう… 期待通りにいかん…

[ethereum] solidityをRopstenにデプロイしたい

$ npm install truffle-hdwallet-provider
$ truffle compile

truffleconfig.js

const HDWalletProvider = require("truffle-hdwallet-provider");
const mnemonic = "";

    ropsten: {
      provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/${project_id}`),
      network_id: 3,       // Ropsten's id
      gas: 5500000,        // Ropsten has a lower block limit than mainnet
      confirmations: 2,    // # of confs to wait between deployments. (default: 0)
      timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50)
      skipDryRun: true     // Skip dry run before migrations? (default: false for public nets )
    },

$ truffle migrate –network ropsten

なるほど、これは凄い

[ethereum] solidityで配列に格納して、値を返却する

Practice.sol
L 構造体Clientのclientsという配列に格納して、excesise関数でweightを-2として返却するコントラクトです。

pragma solidity >= 0.4.0 < 0.7.0;

contract Practice {

	struct Client {
		string name;
		string gender;
		uint256 weight;
		uint256 height;
	}
	Client[] public clients;

	function register(string memory _name, string memory _gender, uint256 _weight, uint256 _height) public returns(uint256 id) {
		id = clients.push(Client(_name, _gender, _weight, _height)) - 1;
		return id;
	}

	function excesise() public returns (uint256 newWeight){
		newWeight = clients[0].weight - 2;
		return newWeight;
	}

}

practice_test.js

	describe("practice()", () => {
		it("returns excesized weight", async() => {
			const practice = await PracticeContract.deployed();
			const expected = 63;
			await practice.register("yamada", "male", 65, 175);
			const actual = await practice.excesise.call();
			
			assert.equal(actual, expected, "Weight should be 63");
		})
	})

Contract: Practice
✓ has been deployed successfully
practice()
✓ returns weight (124ms)

2 passing (184ms)

[ethereum] solidityでtax計算

Practice.sol

contract Practice {

	function hello() external pure returns(string memory) {
		return "Hello, World!";
	}

	function tax(uint256 price) public pure returns(uint256 newPrice){
		 newPrice = price * 11 / 10;
		 return newPrice;
	}
}

practice_test.js

	describe("practice()", () => {
		it("returns tax in price", async() => {
			const practice = await PracticeContract.deployed();
			const expected = "110";
			const actual = await practice.tax(100);
			assert.equal(actual, expected, "should be 110");
		})
	})

$ truffle test

Compiling your contracts…
===========================
> Compiling ./contracts/Migrations.sol
> Compiling ./contracts/Practice.sol
> Artifacts written to /tmp/test-202209-108928-12xhvrv.xr0d
> Compiled successfully using:
– solc: 0.5.16+commit.9c3226ce.Emscripten.clang

Contract: Practice
✓ has been deployed successfully
practice()
✓ returns ‘Hello, World!’
practice()
✓ returns tax in price

3 passing (123ms)

taxのmultiplyは price * 1.1; とするとエラーになるので、price * 11 / 10;としないといけない。
なるほど、中々激しい。

[Ethereum] Solidityの基礎構文 その2

### contractでの宣言

pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
}

uintは符号なし256ビットinteger(正のみ)、uint8、uint16、 uint32などもある

### 構造体

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;
    
    struct Zombie {
        string name;
        uint dna;
    }

}

### 配列
solidityには固定長配列と可変長配列がある

uint[2] fixedArray;

string[5] stringArray;

uint[] dynamicArray;
```
publicな配列にすれば、他のコントラクトもこの配列を読める
```
contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }
    Zonbie[] public zombies;

}

### 関数

function eatHumburgers(string _name, uint _amount) {
	
}

eatHamburgers("vitalink", 100)

実例

    function createZombie(string _name, uint _dna){

    }

### 新しい構造体

Person satoshi = Person(20, "Satoshi");
people.push(satoshi)

people.push(Person(15, "akemi"));

関数の中に書く

    function createZombie(string _name, uint _dna) {
        // ここから始めるのだ
        zombies.push(Zombie(_name, _dna));
    }

### Private/Public
publicの関数は誰でもコントラクトの関数を呼び出して実行できる
以下の様に書くと、contract内の他の関数からのみ読み出せる

uint[] numbers;

function _addToArray(uint _number) private {
	numbers.push(_number);
}

privateの関数はアンダーバー(_)で始めるのが通例

    function _createZombie(string _name, uint _dna) private {
        zombies.push(Zombie(_name, _dna));
    }

### 関数の戻り値

string greeting = "what's up dog";

function sayHello() public returns (string) {
	return greeting;
}

関数で変更するにはviewを使う

function sayHello() public view returns (string) {
	return greeting;
}

テスト

    function _generateRandomDna(string _str) private view returns(uint){
        
    }

### Keccak256
ランダムな256ビットの16進数

    function _generateRandomDna(string _str) private view returns (uint) {
        uint rand = uint(keccak256(_str));
        return rand % dnaModulus;
    }

### 統合

    function createRandomZombie(string _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

### event
ブロックチェーンで何かが生じた時にフロントエンドに伝えることができる
何かあったときにアクションを実行する

event IntegersAdded(uint x, uint y, uint result);

function add(uint _x, uint _y) public {
	uint result = _x + _y;
	IntegersAdded(_x, _y, result);
	return result;
}

js側

YourContract.IntegersAdded(function(error, result) {
  // 結果について何らかの処理をする
})

テスト

    event NewZombie(uint zombieId, string name, uint dna);

    function _createZombie(string _name, uint _dna) private {
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        NewZombie(id, _name, _dna);
    }

### フロントエンド

var abi = ""
var ZombieFactoryContract = web3.eth.contract(abi)
var ZombieFactory = ZombieFactoryContract.at(contractAddress)

#("ourButton").click(function(e) {
	var name = $("#nameInput").val()
	ZombieFactory.createRandomZombie(name)
})

var event = ZombieFactory.NewZombie(function(error, result){
	if(error) return
	generateZombie(result.zombieId, result.name, result.dna)
})

function generateZombie(id, name, dna){
	let dnaStr = String(dna)

	while(dnaStr.length < 16)
		dnaStr = "0" + dnaStr

	let zombieDetails = {
		headChoice: dnaStr.substring(0, 2) % 7 + 1,
	    eyeChoice: dnaStr.substring(2, 4) % 11 + 1,
	    shirtChoice: dnaStr.substring(4, 6) % 6 + 1,
	    skinColorChoice: parseInt(dnaStr.substring(6, 8) / 100 * 360),
	    eyeColorChoice: parseInt(dnaStr.substring(8, 10) / 100 * 360),
	    clothesColorChoice: parseInt(dnaStr.substring(10, 12) / 100 * 360),
	    zombieName: name,
	    zombieDescription: "A Level 1 CryptoZombie",
	}

	return zombieDetails
}

なるほど、ゾンビとかふざけ気味だが、中々のものだな

[Ethereum] Solidityの基礎構文 その1

$ truffle init
$ touch test/practice_test.js

const PracticeContract = artifacts.require("Practice");

contract("Practice", () => {
	it("has been deployed successfully", async() => {
		const practice = await PracticeContract.deployed();
		assert(practice, "contract was not deployed");
	})
})

artifacts.require(“*”) でコンパイル済みのコントラクトを読み込んで操作できる

$ touch contracts/Practice.sol

pragma solidity >= 0.4.0 < 0.7.0;

contract Practice {
	
}

migrationによってcontractがdeployされる
$ touch migrations/2_deploy_practice.js

const PracticeContract = artifacts.require("Practice");

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

contract

pragma solidity >= 0.4.0 < 0.7.0;

contract Practice {

	function hello() external pure returns(string memory) {
		return "Hello, World!";
	}
}

– hello : 関数
– external関数 : practice contactのインターフェイスの一部であり、他のコントラクトから呼び出せるが、コントラクトの中からは呼び出せない。external以外に、internal, public, privateがある。publicは他のコントラクトから呼び出せるし、内部でも呼び出せる。externalをpublicに変更しても結果は同じ。internalとprivateではオブジェクトやthisでは呼び出せない。
– pure, view: コントラクトの変数の状態を変更しない関数 pureはデータを読み込むことも書き込むこともできない viewは読み込むだけ
– memory : 永続ストレージに配置されているものを一切参照しない

なるほど 分解すると分かりやすい

[Ethereum] Ubuntuでmining

まず、Minergateに登録する
https://minergate.com/reg

$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository -y ppa:ethereum/ethereum-qt
$ sudo add-apt-repository ppa:ethereum/ethereum
$ sudo add-apt-repository ppa:ethereum/ethereum-dev
$ sudo apt-get update
$ sudo apt-get install ethminer
$ sudo apt-get install ethminer
Reading package lists… Done
Building dependency tree
Reading state information… Done
E: Unable to locate package ethminer
これだと上手くいかない

$ sudo apt install nvidia-cuda-toolkit
$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2019 NVIDIA Corporation
Built on Sun_Jul_28_19:07:16_PDT_2019
Cuda compilation tools, release 10.1, V10.1.243

$ mkdir ethminer
$ wget -O ethminer/ethminer.tar.gz https://github.com/ethereum-mining/ethminer/releases/download/v0.18.0/ethminer-0.18.0-cuda-9-linux-x86_64.tar.gz
$ tar xzf ethminer/ethminer.tar.gz -C ethminer/
$ ethminer/bin/ethminer –help
$ ethminer/bin/ethminer -U -P stratum+tcp://eth.pool.minergate.com:45791/*@gmail.com

なるほど 手順はわかった
あとはsolidityの基礎とreact, truffle周りかな

[Ethereum] ERC721トークン

ERC721は、スマートコントラクト内でNon-Fungible Tokenを扱えるようにしたもの

pragma solidity ^0.4.23;

import "github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC721/ERC721Full.sol";
import "github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC721/ERC721Mintable.sol";
import "github.com/OpenZeppelin/openzeppelin-solidity/contracts/ownership/Ownable.sol";

contract MyTokenCollection is ERC721Full, ERC721Mintable, Ownable {
	
	constructor() public ERC721Full("MyTokenCollection", "MTC"){}

	function mintTokenCollection(string _tokenURI) public {
		uint256 newTokenId = _getNextTokenId();
		_mint(msg.sender, newTokeId);
		_setTokenURI(newTokenId, _tokenURI);
	}

	function _getNextTokenId() private view returns(uint256){
		return totalSupply().add(1);
	}
}

なるほど、Truffleもう一回ちょっとやり直す必要があるかな
Reactの勉強もしないといけないか…

[Ethereum] Reactでdappを作りたい

$ sudo npm install -g create-react-app
$ create-react-app lottery-react
$ cd lottery-react
$ npm run start

http://192.168.34.10:3000/

$ sudo npm install -g yarn
$ yarn -v
1.22.5
$ npm install –save web3@1.0.0-beta.26

$ cd ..
$ mkdir lottery
$ cd lottery
$ sudo npm install solc@0.4.17
$ npm install –save mocha ganache-cli web3@1.0.0-beta.26
$ npm install –save truffle-hdwallet-provider@0.0.3

contract/Lottery.sol

pragma solidity ^0.4.17;

contract Lottery {
	address public manager;
	address[] public players;

	function Lottery () public {
		manager = msg.sender;
	}

	function enter() public payable {
		require(msg.value > .01 ether);

		players.push(msg.sender);
	}

	function random() private view return (uint) {
		return uint(keccak256(block.difficulty, now, players));
	}

	function pickWinner() public restricted {
		uint index = random() % players.length;
		players[index].transfer(this.balance);
		players = new address[](0);
	}

	modifier restricted() {
		require(msg.sender == manager);
		_;
	}

	function getPlayers() public view returns(address[]){
		return players;
	}
}

compiler.js

const path = require('path');
const fs = require('fs');
const solc = require('solc');

const IndexPath = path.resolve(__dirname,'contracts', 'Lottery.sol');
const source = fs.readFileSync(IndexPath, 'utf8');

console.log(solc.compile(source,1));

ABIとは、Application Binary Interface

lottery.js

import web3 from './web3';

const address = '0xaC24CD668b4A6d2935b09596F1558c1E305F62F1';


const abi = [{
    "constant": true,
    "inputs": [],
    "name": "manager",
    "outputs": [{
        "name": "",
        "type": "address"
    }],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
}, {
    "constant": false,
    "inputs": [],
    "name": "pickWinner",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
}, {
    "constant": true,
    "inputs": [],
    "name": "getPlayers",
    "outputs": [{
        "name": "",
        "type": "address[]"
    }],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
}, {
    "constant": false,
    "inputs": [],
    "name": "enter",
    "outputs": [],
    "payable": true,
    "stateMutability": "payable",
    "type": "function"
}, {
    "constant": true,
    "inputs": [{
        "name": "",
        "type": "uint256"
    }],
    "name": "players",
    "outputs": [{
        "name": "",
        "type": "address"
    }],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
}, {
    "inputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "constructor"
}];


export default new web3.eth.Contract(abi, address);

web3.js

import Web3 from 'web3';

const web3 = new Web3(window.web3.currentProvider);

export default web3;

App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import web3 from './web3';
import lottery from './lottery';

class App extends Component {
  state = {
    manager: '',
    player: [],
    balance: '',
    value: '',
    messaget: ''
  };

  async componentDidMount() {
    const manager = await lottery.methods.manager().call();
    const players = await lottery.methods.getPlayers().call();
    const balance = await web3.eth.getBalance(lottery.opetions.address);

    this.setState({manager, players, balance});
  }

  onSubmit = async(event) => {
    event.preventDefault();

    const accounts = await web3.eth.getAccounts();

    this.setState({message: 'Waiting on transaction success...'});

    await lottery.methods.enter().send({
      from: accounts[0],
      value: web3.utils.toWei(this.state.value, 'ether')
    });

    this.setState({message: 'you have been entered!'});
  };

  onClick = async() => {
    const accounts = await web3.eth.getAccounts();

    this.setState({message: "waiting on transaction success..."});

    await lottery.methods.pickWinner().send({
      from: accounts[0]
    });

    this.setState({message: 'A winner has been picked'});
  };

  render() {
    return (
    <div>
      <h2>Lottery Contract</h2>
      <p>
        This contract is managed by {this.state.manager}.
        There are currently {this.state.players.length} peple entered,
        competing to win {web3.utils.fromWei(this.state.balance, 'ether')}
      </p>
      <hr />

        <form onSubmit={this.onSubmit}>
            <h4>Want to try your luck?</h4>
            <div>
              <label>Amount of ether to enter</label>
              <input
              value = {this.state.value}
                onChange={event => this.setState({ value: event.target.value })}
              />
            </div>
            <button>Enter</button>
        </form>

        <hr />

        <h4>Ready to pick a winner?</h4>
        <button onClick={this.onClick}>Pick a winner!</button>

        <hr />
        <h1>{this.state.message}</h1>
      </div>
  );
  }
}

export default App;

なるほど、全体の流れはわかった