[Ethereum] wallet address, mnemonicの作成

Ethereum uses ECDSA to generate public-private key pairs as Bitcoin does.
Ethereum address is generated by hashing public key with keccak256, slicing last 20 bytes, and adding “0x” at the top.

privateKey -> derive with ECDSA -> publicKey -> hash -> Ethereum address

const Web3 = require("web3");

const mnemonic = "*";

const HDWalletProvider = require('truffle-hdwallet-provider');
let provider = new HDWalletProvider(mnemonic, 'https://ropsten.infura.io/v3/*', 0, 1);

let web3 = new Web3(provider);

let account = web3.eth.accounts.create();

console.log("address:" + account.address);
console.log("privateKey:" + account.privateKey);

$ node address.js
address:0xefC5B5d9A4BDA3bE4f4da8e7AaFe25F08C5EAce7
privateKey:********
$ node address.js
address:0xB19C2356a88F5437e253d404DA642EC914dCC794
privateKey:********

ニーモニック(mnemonic)はあるだけで口座管理ができる
キーストアはパスワードがないと何も出来ない
MetaMaskのウォレットではmnemonicから秘密鍵を作る仕組みがある

### mnemonic
12ワードは128bitのエントロピーから生成される(randomな値)
エントロピーからチェックサムを生成し足し合わせバイト列に変換し11bit(最大2048)ごとに分割
分割した値をindex値としてワードリストの索引
PBKDF2-SHA512から生成 2048回ストレッチ

なるほど、中々凄いことになってるわ

[Bitcoin] Walletの概要

秘密鍵 => 公開鍵 => ビットコインウォレットの順番で作られる。
OpenSSLで秘密鍵、公開鍵を作る手順と一緒
ウォレットは、「秘密鍵」「公開鍵」を保持し、管理する

### ウォレットの鍵の管理手法
ランダムウォレット と HDウォレットがある

– ランダムウォレット
秘密鍵公開鍵を1:1の関係で生成し管理する
ただし、複数の秘密鍵を管理保持しなければならない

– HDウォレット(Hierarchy Deterministic)
シードと呼ばれる値から秘密鍵を生成し、階層構造を用いて管理する
シードがあれば、秘密鍵は複数管理する必要はない(管理コストが下がる)

乱数生成器 -> シード -> HMAC-SHA512 -> 親秘密鍵(256bit) + 親ChainCode(256bit) *子秘密鍵生成に使用

親秘密鍵 + 親ChainCode + index -> HMAC-SHA512 -> 子秘密鍵 + 子ChainCode

### パスフレーズ, BIP32, BIP44
パスフレーズとは、どの階層にどの鍵が存在するのかを一意に表したものでスラッシュ区切りで表現
BIP32の標準規格: m/a’/c/i
BIP44の標準規格: m / purpose’ / coin_type’ / account’ / change /

### HMAC-sha512
HMACは、暗号ハッシュ関数を使用して、メッセージ認証を行う仕組み

import hmac
import hashlib
key="asdf"
text="public text"
signature = hmac.new(bytearray(key, "ASCII"),bytearray(text, "ASCII"), hashlib.sha512).hexdigest()
print(signature)

$ python3 wallet.py
b83ed32cab16c05e43f0922cf5123f04d2278d4fa50e4b1edab5f0ce04e74d5900b91dec501efd96de4721313f56533b55c1fec837b92bebe6126df7838dcc6d

### bitcoinのlibraryを使う場合

from bitcoin import *
my_private_key = random_key()
print(my_private_key)
public_key = privtopub(my_private_key)
print(public_key)
wallet_address = pubtoaddr(public_key)
print(wallet_address)

秘密鍵 => 公開鍵 => ビットコインウォレットの順番で作る

$ python3 wallet.py
336a4393ccef96b9eedb78deff766a6289d6e47983b35ee58860dd65c1a8fb86
04ef2a745e5853cea83031dd5a49de1716642ae55b1d537d2407f52757580071d7475b61b4efa2fa355d50251a286850a8548f808440c8e3739aa8bf31660dfab3
1FegPWcNYxpVMRg8rT8NhWXkzWAuk6WX2A

ああああああああああ
もうやだあ

[Ethereum] contractのdeploy その2

sample_greeting.sol

contract SampleGreeting {
	string greeting = 'Hello World';

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

$ sudo snap install solc
$ solc –bin –abi sample_greeting.sol
sample_greeting.sol:1:1: Warning: Source file does not specify required compiler version! Consider adding “pragma solidity ^0.5.16;”
contract SampleGreeting {
^ (Relevant source part starts here and spans across multiple lines).

======= sample_greeting.sol:SampleGreeting =======
Binary:
60806040526040518060400160405280600b81526020017f48656c6c6f20576f726c640000000000000000000000000000000000000000008152506000908051906020019061004f929190610062565b5034801561005c57600080fd5b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b61018a806101166000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063d705a4b514610030575b600080fd5b6100386100b3565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561007857808201518184015260208101905061005d565b50505050905090810190601f1680156100a55780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b606060008054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561014b5780601f106101205761010080835404028352916020019161014b565b820191906000526020600020905b81548152906001019060200180831161012e57829003601f168201915b505050505090509056fea265627a7a72315820be61e923cb4240e17bacc0ab36f4b2a0e91dd3c77c284e3edcc3bbcbc6e5079564736f6c63430005100032
Contract JSON ABI
[{“constant”:true,”inputs”:[],”name”:”getGreet”,”outputs”:[{“internalType”:”string”,”name”:””,”type”:”string”}],”payable”:false,”stateMutability”:”view”,”type”:”function”}]

const Web3 = require('web3');

const mnemonic = "*";

const HDWalletProvider = require('truffle-hdwallet-provider');
let provider = new HDWalletProvider(mnemonic, 'https://ropsten.infura.io/v3/*', 0, 1);

let web3 = new Web3(provider);

let bin = '0x60806040526040518060400160405280600b81526020017f48656c6c6f20576f726c640000000000000000000000000000000000000000008152506000908051906020019061004f929190610062565b5034801561005c57600080fd5b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b61018a806101166000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063d705a4b514610030575b600080fd5b6100386100b3565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561007857808201518184015260208101905061005d565b50505050905090810190601f1680156100a55780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b606060008054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561014b5780601f106101205761010080835404028352916020019161014b565b820191906000526020600020905b81548152906001019060200180831161012e57829003601f168201915b505050505090509056fea265627a7a72315820be61e923cb4240e17bacc0ab36f4b2a0e91dd3c77c284e3edcc3bbcbc6e5079564736f6c63430005100032';
let abi = [{"constant":true,"inputs":[],"name":"getGreet","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}];
let data = {
	'data': bin
}

let contract = new web3.eth.Contract(abi, null, data);
console.log('contract:', contract);

$ node sample.js
///
_jsonInterface:
[ { constant: true,
inputs: [],
name: ‘getGreet’,
outputs: [Array],
payable: false,
stateMutability: ‘view’,
type: ‘function’,
signature: ‘*’ } ] }

signatureの値をメモしておく

web3.eth.getGasPrice().
	then((averageGasPrice) => {
		console.log("gasPrice: " + averageGasPrice);
	}).catch(console.error);

web3.eth.getAccounts((error, result) => {
	console.log('result: ', result);

	web3.eth.getTransactionCount(result[0], (error, response)=>{
		console.log('nonce:', response);
	})
})

contract.deploy().estimateGas().
	then((estimatedGas) => {
		console.log("gas: " + estimatedGas);
	}).catch(console.error);

$ node sample.js
result: [ ‘*’ ]
gasPrice: 1500000013
gas: 164431
nonce: 3

let sender_address = "*";
let nonce = '3';
let chainId = '3';
let gas = 164431;
let gasPrice = '1500000013'

let tx = {
  'from': sender_address,
  'nonce': nonce,
  'chainId': chainId,
  'gas': gas,
  'gasPrice': gasPrice,
  'data': bin,
}

const PRIVATE_KEY = "*";

web3.eth.accounts.signTransaction(tx, PRIVATE_KEY, (error, response)=>{
    console.log(response);
});

{ messageHash:
‘0x71d7*’,
v: ‘0x2a’,
r:
‘0xd04f9c44192de22c1088feccc*’,
s:
‘0x593a5ec5a50d1d5bed367*’,
rawTransaction:
‘0xf902f2038459682f0d8302824f8080b902a060806040526040518060400160405280600b81526020017f48656c6c6f20576f726c640000000000000000000000000000000000000000008152506000908051906020019061004f929190610062565b5034801561005c57600080fd5b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b61018a806101166000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063d705a4b514610030575b600080fd5b6100386100b3565b604051808060200182810*’,
transactionHash:
‘0x55a06ab424128b04b9002fe7de1a17e8981d94728bac06dd55993cfdba1b860d’ }

デプロイ

let raw = '0xf902f2038459682f0d8302824f8080b902a060806040526040518060400160405280600b81526020017f48656c6c6f20576f726c640000000000000000000000000000000000000000008152506000908051906020019061004f929190610062565b5034801561005c57600080fd5b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b61018a806101166000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063d705a4b514610030575b600080fd5b6100386100b3565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561007857808201518184015260208101905061005d565b50505050905090810190601f1680156100a5578082038051600183*';

web3.eth.sendSignedTransaction(raw).on('receipt', console.log);

$ node sample.js
{ blockHash:
‘0x8414d2fac3b36315828b7d330287a181e3b58ac29ee5d1325fb27b6d92dc03d1’,
blockNumber: 11682111,
contractAddress: ‘0x31695391C6C0f3A3F2EDe7cDb9B13Da277A8e2Eb’,
cumulativeGasUsed: 1680291,
effectiveGasPrice: ‘0x59682f0d’,
from: ‘0x71c9f1d5be00173ae7b774bdbe2112cdd03c5c92’,
gasUsed: 164431,
logs: [],
logsBloom:
‘0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000’,
status: true,
to: null,
transactionHash:
‘0x55a06ab424128b04b9002fe7de1a17e8981d94728bac06dd55993cfdba1b860d’,
transactionIndex: 13,
type: ‘0x0’ }

web3.eth.getAccounts((error, result)=> {
	let sender_address = result[0]
	let call_data = {
		'from': sender_address,
		'to': recipient_address,
		'data': signature
	}

	web3.eth.call(call_data, (error, response) => {
		console.log('response: ', response);
		provider.engine.stop();
	})
})

$ node sample.js
response: 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000

おおおお なるほど
solidityでcompileしたデータを、from, nonce, chainId, gas, gasPriceなどと一緒にトランザクションにして秘密鍵で署名してデプロイしてるのね。

一連の流れはわかった!

[Ethereum] シンプルなスマートコントラクトをデプロイ

$ mkdir rinkeby
$ cd rinkeby
$ npm init

{
  "name": "inbox",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

solidityのcompilerをinstall
$ npm install –save solc

mocha(テストフレーム)をinstall
$ npm install –save mocha ganache-cli web3@1.0.0-beta.26

truffle-hdwallet-providerをインストール
$ npm install –save truffle-hdwallet-provider@0.0.3

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

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

moudle.exports = solc.compile(source,1).contracts[':Inbox'];

Inbox.sol

pragma solidity ^0.8.11;

contract Inbox {
	string public message;

	function Inbox(string initialMessage) public {
		message = initialMessage;
	}

	function setMessage(string newMessage) public {
		message = newMessage;
	}
}

deploy.js

const HDWalletProvider = require('truffle-hdwallet-provider');
const Web3 = require('web3');
const { interface, bytecode } = require('./compile');

const provider = new HDWalletProvider (
	'harmonic',
	'https://ropsten.infura.io/v3/*'
);

const web3 = new Web3(provider);

const deploy = async () => {

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

	console.log('Attempting to deploy from account', accounts[0]);

	const result = await new web3.eth.Contract(JSON.parse(interface))
		.deploy({data: bytecode, arguments:['Hi there!']})
		.send({gas:'1000000', from: accounts:[0]});

	console.log('Contract deploy to', result.options.address);
}

$ node deploy.js
Attempting to deploy from account *
(node:408216) UnhandledPromiseRejectionWarning: Error: intrinsic gas too low

うーむ、gasの設定の方法がよくわかん
gasの概念の理解が先か…

[話者認識] i-vectorとは

GMMスーパーベクトルは、時系列データである発話をベクトル空間上の一点として表現するもの
i-vectorもこのGMMスーパーベクトルを基礎としている
識別モデルアプリーチから因子分析アプローチに転換している
話者以外の要因を緻密にモデル化し除去し用としても限界があった
話者とチャンネル因子xの空間にGMMスーパーベクトルを写像する因子分析モデルを提案した。この写像がi-vector 全因子wの事後分布の平均値E[w]として得られる

### i-vectorによる話者照合
1.登録話者i-vector w1と照合話者のi-vector w2のコサイン類似度によりスコアリングを行う
SVM同等以上の性能
2. i-vector w1, w2を用いて、同一モデルから生成されたか否かの仮説を評価

### sidekit
$ mkdir i-vector
$ cd i-vector
$ pip3 install sidekit

import sidekit

fa = sidekit.FactoryAnalyser()

fa.total_variability_single(stat_server_filename,
	ubm,
	tv_rank,
	nb_iter=20,
	min_div=True,
	tv_init=None,
	batch_size=300,
	save_init=False,
	output_file_name=None)

$ python3 main.py
Traceback (most recent call last):
File “main.py”, line 3, in
fa = sidekit.FactoryAnalyser()
AttributeError: module ‘sidekit’ has no attribute ‘FactoryAnalyser’

あれ、何かがおかしい

[Ethereum] じゃんけんゲームをして勝ったらEthereumを貰える

Rapstonだと、送金処理ができなかったので、private netに接続します。
勝った時のみ、Etherの送金処理を実行します。

<div class="container">
	<h1>Ethereum</h1>
	<div id="balanceArea"></div>
	<br><br>
	<h1>じゃんけん</h1>
	<button onclick="R_Click(0)">グー</button>
	<button onclick="R_Click(1)">チョキ</button>
	<button onclick="R_Click(2)">パー</button>
	<br><br>
	<div id="area1"></div>
	<div id="area2"></div>
	</div>
	<script>
		let balanceArea = document.getElementById('balanceArea');
		const web3 = new Web3();
		const userWallet = "";
		const adminWallet = "";
		web3.setProvider(new web3.providers.HttpProvider('http://192.168.33.10:8545'));

		function R_Click(p_janken_r){
			let janken = ["グー","チョキ","パー"];
			let janken_r = Math.floor(Math.random()*3);

			let p_janken = ["グー","チョキ","パー"];

       if (janken_r === p_janken_r) {
				Result_end = "あいこです";
			} else if(p_janken_r === 0 && janken_r === 1) {
				Result_end = "あなたの【勝ち】"; 
				win();
			} else if(p_janken_r === 1 && janken_r === 2) {
				Result_end = "あなたの【勝ち】"; 
				win();
			} else if(p_janken_r === 2 && janken_r === 0) {
				Result_end = "あなたの【勝ち】";
				win();
			} else {
				Result_end = "あなたの【負け】";
				lose();
			}
			document.getElementById("area1").innerHTML = p_janken[p_janken_r] +"を選択しました。ジャンケンの結果は・・・?<br><br>";
            document.getElementById("area2").innerHTML = "相手は" + janken[janken_r] + "! "+ Result_end;
		}
		
		main();

		async function main(){
			web3.eth.getBalance(adminWallet).then((result, error) => {
				const balance = web3.utils.fromWei(result, 'ether');
				console.log(balance);
				balanceArea.innerHTML = balance + " eth";
			});
		}

		async function win(){
			console.log("win");
			var balance = web3.eth.sendTransaction({from: userWallet, to:adminWallet, value:200});
			console.log(balance);
			main();
		}

		async function lose(){
			main();
		}
		
	</script>

トランザクションが生成されてブロックで承認されないと送金処理は実行されないので、じゃんけんに勝っても直ぐにはbalanceに反映されない。

なるほど、理解が深まった。

[Ethereum] Web3.jsでMainnetやRopsten Networkに接続する方法

infura.ioで新規にprojectを作成する
https://infura.io/dashboard

projectのendpointをメモする

メモしたendpointに接続する

<script src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.7.0-rc.0/web3.min.js"></script>
	<script>
		var web3 = new Web3();
		web3.setProvider(new web3.providers.HttpProvider('https://mainnet.infura.io/v3/*'));
		var _balance = web3.eth.getBalance("${wallet address}");
		console.log(_balance)
	</script>

なるほどー 殆ど謎が解けた

[Ethereum] CryptoKitiies

CryptoKitties
https://www.cryptokitties.co/

ソースコード
-> contractが公開されている
https://etherscan.io/address/0x06012c8cf97bead5deae237070f9587f8e7a266d#code

contractを継承

contract KittyAccessControl
contract KittyBase is KittyAccessControl
contract KittyOwnership is KittyBase, ERC721
contract KittyBreeding is KittyOwnership
contract KittyAuction is KittyBreeding
contract KittyMinting is KittyAuction
contract KittyCore is KittyMinting
function setGeneScienceAddress(address _address) external onlyCEO {
        GeneScienceInterface candidateContract = GeneScienceInterface(_address);

        // NOTE: verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117
        require(candidateContract.isGeneScience());

        // Set the new contract address
        geneScience = candidateContract;
    }

function giveBirth(uint256 _matronId)
        external
        whenNotPaused
        returns(uint256)
    {
        // Grab a reference to the matron in storage.
        Kitty storage matron = kitties[_matronId];

        // Check that the matron is a valid cat.
        require(matron.birthTime != 0);

        // Check that the matron is pregnant, and that its time has come!
        require(_isReadyToGiveBirth(matron));

        // Grab a reference to the sire in storage.
        uint256 sireId = matron.siringWithId;
        Kitty storage sire = kitties[sireId];

        // Determine the higher generation number of the two parents
        uint16 parentGen = matron.generation;
        if (sire.generation > matron.generation) {
            parentGen = sire.generation;
        }

        // Call the sooper-sekret gene mixing operation.
        uint256 childGenes = geneScience.mixGenes(matron.genes, sire.genes, matron.cooldownEndBlock - 1);

        // Make the new kitten!
        address owner = kittyIndexToOwner[_matronId];
        uint256 kittenId = _createKitty(_matronId, matron.siringWithId, parentGen + 1, childGenes, owner);

        // Clear the reference to sire from the matron (REQUIRED! Having siringWithId
        // set is what marks a matron as being pregnant.)
        delete matron.siringWithId;

        // Every time a kitty gives birth counter is decremented.
        pregnantKitties--;

        // Send the balance fee to the person who made birth happen.
        msg.sender.send(autoBirthFee);

        // return the new kitten's ID
        return kittenId;
    }

uint256 childGenes = geneScience.mixGenes(matron.genes, sire.genes, matron.cooldownEndBlock – 1); の mixGenesで配合している

[Blockchain] Ubuntu20.04・OpenSSLで秘密鍵公開鍵の操作

$ openssl version
OpenSSL 1.1.1f 31 Mar 2020

### 秘密鍵の作成
$ openssl ecparam -genkey -name secp256k1 -out private.pem
// ecparamは楕円曲線暗号における楕円曲線パラメータに関するサブコマンド
$ cat private.pem
—–BEGIN EC PARAMETERS—–
BgUrgQQACg==
—–END EC PARAMETERS—–
—–BEGIN EC PRIVATE KEY—–
MHQCAQEEINB5OV0K2ggkM2a0bmVTcj7FioqK5TDI9NJAxgOUjcFOoAcGBSuBBAAK
oUQDQgAELnHK99GtgUL9F3Q5YSwYa5ZdI8uY0P5diBTZZN4Ld7feo13zqYO9oQm3
G1YHB2ITeG81+KridKnVOzDk0RwA7w==
—–END EC PRIVATE KEY—–

### 公開鍵の作成
$ openssl ec -in private.pem -pubout -out public.pem
// echは楕円曲線暗号に関するサブコマンド
read EC key
writing EC key
$ cat public.pem
—–BEGIN PUBLIC KEY—–
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELnHK99GtgUL9F3Q5YSwYa5ZdI8uY0P5d
iBTZZN4Ld7feo13zqYO9oQm3G1YHB2ITeG81+KridKnVOzDk0RwA7w==
—–END PUBLIC KEY—–

### メッセージの作成、ハッシュ化
$ sha256sum test.txt | cut -c1-64 > hashed.txt
$ cat hashed.txt
d8aa344276524074fbfec2249bedb89a5ddccc9dc57504e92a9963f48bdf68d1

### verify
ハッシュ化した書類と秘密鍵でhashed.sigを作成し、公開鍵とhashed.sigで検証する
$ openssl dgst -SHA256 -sign private.pem hashed.txt > hashed.sig
// dgstはメッセージダイジェストを計算
$ ls
hashed.sig hashed.txt private.pem public.pem test.txt
$ openssl dgst -SHA256 -verify public.pem -signature hashed.sig hashed.txt
Verified OK

apostilleのことだね

[Ethereum] RemixとMetamask, Rapsten networkの使い方

1. ブラウザでRemixのサイトを開く
https://remix.ethereum.org/#optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.7+commit.e28d00a7.js

2. 左メニューでイーサのマークをクリックし、Injected web3を選択する

3. contractを作成し、compilerを0.4.16に合わせてコンパイル

4. 1億tmcnをdeploy
100000000, “Timecoin”, “TMCN”

5. metamaskに通知が来るのでconfirm

6. deployされる

7. Etherscanでtransactionが確認できる

8. Metamaskのtoken importでcontractのhashを入力し、トークンをインポートする

9. MyEtherWalletにログイン
timecoin, tmcnが入っているのがわかる

10. tachyon walletをインストール

11. QRコードでコントラクトをQRコード化する
QRコード作成サイト
https://www.cman.jp/QRcode/qr_make/
{ERC20:0xeE19196D02D69012c4e7Ce962B528360681F8E36}

12. tachyon walletで networkをRopstenにして、新しい通貨を追加

13. MetaMaskからtachyon walletのアドレスに向けて送信

14. tachyon walletで受け取り

おおおおおおおおおおおおおおおおおお
大分概念を理解した^^
Ethを動かした方が早いですね