diff --git a/jp/10/00-overview.md b/jp/10/00-overview.md new file mode 100644 index 0000000000..d69942a250 --- /dev/null +++ b/jp/10/00-overview.md @@ -0,0 +1,26 @@ +--- +title: "Truffleを使ってDAppsをデプロイする" +header: "Truffleを使ってDAppsをデプロイする" +roadmap: roadmap.jpg +path: solidity_advanced +position: 2 +publishedOn: Cryptozombies +--- + +スマートコントラクトをデプロイする方法を教えると約束したことを覚えているか? + +時間はかかったが、ついにその時が来たぞ! + +このレッスンでは **_Truffle_** を使って **_Ethereum_** にデプロイする方法を学ぶのだ。 + +加えて、お前のスマートコントラクトを **_Loom_** にデプロイする方法も伝授するぞ😎。 + +なぜ **_Loom_** かだと?結局ところ、 **_イーサリアム_** は最高に安全なネットワークだ。 + +ああ、我々はそこについて異論はない。しかしだ。イーサリアムは取引のたびに _ガス_ を消費するだろう。するとお前のユーザーは取引ごとにフィー(手数料)を支払わなければならないのだ。しかもユーザーは取引が完了するまでに最低でも10秒待たなければならない。 + +一言で言えば、 **_イーサリアム上の全ての取引は、平等にセキュリティの保証を受けている_** ということだ。ユーザー向けのDAppやゲームなんかだと、このセキュリティレベルは必要ないだろう。実際、ユーザーエクスペリエンスを損なうだけなのだ。 + +**_Loom_** 上では、ユーザーははるかにスピーディーかつガス代のかからない取引ができる。ユーザー向けのDAppやゲームには最適じゃないか。 + +話は終わりだ!とりかかるぞ😉 diff --git a/jp/10/01.md b/jp/10/01.md new file mode 100644 index 0000000000..0d009c2171 --- /dev/null +++ b/jp/10/01.md @@ -0,0 +1,53 @@ +--- +title: イントロダクション +actions: ['答え合わせ', 'ヒント'] +requireLogin: true +material: + terminal: + help: + You should probably run `npm install truffle -g`. + commands: + "npm install truffle -g": + hint: npm install truffle -g + output: | + /usr/local/bin/truffle -> /usr/local/lib/node_modules/truffle/build/cli.bundled.js + + truffle@4.1.14 + added 81 packages from 311 contributors in 5.104s +--- + +もしお前が **CryptoZombies** を始めたばかりなら、ビギナー向けの6レッスンを先に受けることを勧める。時間をかけてでもスマートコントラクトの開発に慣れるのだ。そこを飛ばすと、このレッスンは非常に厳しいものになるぞ。 + +## 欠けたピース + +お前は前のレッスンをクリアしたということだな。素晴らしいじゃないか!お前はすでにDAppsを構築する技術をほぼ習得したということだ。 + +しかし!重要なピースがまだ欠けているぞ。 + +そうだ…お前は **_スマートコントラクトをデプロイする方法_** を学ばねばなるまい。 + +フロントエンド開発の経験があれば、 *WebpackやGulp、Browserify* などの開発者を楽にするツールに慣れているだろう。 + +では **Solidity** の開発者はどんなツールを使っているのか? + +## Truffle + +**_Truffle_** は最も有名なブロックチェーン開発のフレームワークだ。その理由は、便利機能が満載だからだ: + +- スマートコントラクトのコンパイルを簡素化 +- ABI自動生成 +- スマートコントラクトのテストを統合 - **Mocha** や **Chai** をサポートしているぞ! +- 複数のネットワークをサポート - コードはRinkeby、 **_Ethereum_** 、そして **_Loom_** にもデプロイできる。これについては後ほど説明してやろう。 + +`npm` と `node` をすでにインストールしているなら、 **Truffle** をグローバルインストールするのだ。 + +# さあテストだ + +まずは、新しいターミナルウインドウを立ち上げ、`CryptoZombies`というディレクトリを作成し、`cd`でディレクトリの中に入るのだ。 + +1. さあ、 **Truffle** をグローバルインストールするぞ。 + + > 注: ここに`npm`でパッケージをグローバルインストールするコマンドを示すぞ: + + ```bash + npm install package_name -g + ``` diff --git a/jp/10/02.md b/jp/10/02.md new file mode 100644 index 0000000000..4253ca089d --- /dev/null +++ b/jp/10/02.md @@ -0,0 +1,87 @@ +--- +title: Getting Started with Truffle +actions: ['答え合わせ', 'ヒント'] +requireLogin: true +material: + terminal: + help: | + First, you should probably run `truffle init`. Next, execute `npm install truffle-hdwallet-provider` + commands: + "truffle init": + hint: truffle init + output: | + Downloading... + Unpacking... + Setting up... + Unbox successful. Sweet! + + Commands: + + Compile: truffle compile + Migrate: truffle migrate + Test contracts: truffle test + "npm install truffle-hdwallet-provider": + hint: npm install truffle-hdwallet-provider + output: | + + truffle-hdwallet-provider@0.0.6 + added 1 package from 1 contributor and audited 71402 packages in 5.612s + found 0 vulnerabilities +--- + +**Truffle** のインストールが終わったら、次は`truffle init`コマンドを叩いて、我々のプロジェクトを初期化するぞ。このコマンドは、フォルダーと設定ファイルを以下のような構成で作成してくれる: + +``` +├── contracts + ├── Migrations.sol +├── migrations + ├── 1_initial_migration.js +└── test +truffle-config.js +truffle.js +``` + +Contracts, migrations, tests... ややこしいな😟 + +心配するな。 **Truffle** の使い方を学んでいるからと言って、ゾンビに脳みそを食べられたりしない。この章では **Truffle** のデフォルトのプロジェクト構成を紹介する。一旦 **Truffle** の使い方を知ってしまえば、スマートコントラクトのデプロイなんて朝飯前になるぞ。 + +## Truffleのデフォルトのディレクトリー構成 + +さあ、`CryptoZombies`ディレクトリーの中で`truffle init`コマンドを叩いて、いくつかのディレクトリーとJavaScript、Solidityのファイルを作成するのだ。詳しく見ていくぞ: + + - **_contracts_**: ここに我々のスマートコントラクトのコードを全て置く。コードを整理するには、`contracts/tokens`というように子フォルダーを作成すればいい😉。 + + > 注: `truffle init`コマンドは自動的に`Migrations.sol`という名前のコントラクトとそれに対応するマイグレーションファイルを作成する。この説明は後だ。 + + - **_migrations_**: ここにはJavaScriptで書かれたマイグレーションファイルが置かれている。 **Truffle** がスマートコントラクトにデプロイする際の設定が書かれているぞ。 + + - **_test_**: ここにテストコードを置く。テストコードはJavaScript か Solidityで書かなければならない。コントラクトはデプロイしたら変更できないことを覚えているか?デプロイ前にスマートコントラクトをテストすることが不可欠だ。 + + - **_truffle.js_** and **_truffle-config.js_**: ここにはデプロイ用のネットワーク設定ファイルが置かれている。`truffle.js` と `truffle-config.js`の内容は同じだ。Windows環境では`truffle.js` と `truffle.exe`が同じフォルダーにあると競合してしまう。お前がWindowsを使っているなら、`truffle.js`を削除し、`truffle-config.js`をデフォルトの設定ファイルにするのだ。詳しく知りたければTruffleの公式ドキュメントを訪ねるといい。 + + +こんなディレクトリー構成を使わなければならないのか?不慣れだし、ややこしく見える… + +それには2つ理由がある。1つ目は、これらのフォルダーの名前を変えてしまうと、 **Truffle** が期待通りに動かなくなる。 + +2つ目は、この構成ルールに従うことで、他の開発者がお前のプロジェクトを理解しやすくなるということだ。標準のフォルダー構成とコーディング規則を使えば、配布したりチームメンバを変えたりした時に役立つだろう。 + + +## truffle-hdwallet-provider + +このレッスンでは、 _Infura_ を使ってコードを **_Ethereum_** にデプロイする。この方法を使えば、アプリを動かすのに **_Ethereum_** のノードやウォレットを独自にセットアップする必要がなくなるのだ。 +しかし、安全面から、 _Infura_ は秘密鍵の管理をしない。つまり、我々に代わって取引に署名することはできないということだ。**Truffle** に署名を要求するスマートコントラクトをデプロイするためには、 `truffle-hdwallet-provider` というツールを使うぞ。このツールの唯一の目的は、取引に署名処理を施すことだ。 + +> 注: もしかしたら前の章で `truffle-hdwallet-provider` を次のようなコマンドを叩いてインストールしなかったことを不思議に思っているかもしれない: + + ```JavaScript + npm install truffle truffle-hdwallet-provider + ``` + +そう…`truffle init`コマンドを叩くには、空のディレクトリーである必要があるのだ。もし1つでもファイルが存在すれば、エラーになってしまう。従って、手順通りに`truffle init`をした後に`truffle-hdwallet-provider`をインストールしなければならないのだ。 + + +# さあテストだ + +1. `truffle init`コマンドを叩け。先ほど説明したようなディレクトリー構成を作ってくれるだろう。 + +2. `npm install truffle-hdwallet-provider`コマンドを叩け。 diff --git a/jp/10/03.md b/jp/10/03.md new file mode 100644 index 0000000000..7902896bde --- /dev/null +++ b/jp/10/03.md @@ -0,0 +1,115 @@ +--- +title: ソースコードをコンパイルする +actions: ['答え合わせ', 'ヒント'] +requireLogin: true +material: + terminal: + help: + You should probably run `truffle compile`. + commands: + "truffle compile": + hint: truffle compile + output: | + Compiling ./contracts/Migrations.sol... + Compiling ./contracts/CryptoZombies.sol... + Compiling ./contracts/erc721.sol... + Compiling ./contracts/ownable.sol... + Compiling ./contracts/safemath.sol... + Compiling ./contracts/zombieattack.sol... + Compiling ./contracts/zombiefactory.sol... + Compiling ./contracts/zombiefeeding.sol... + Compiling ./contracts/zombiehelper.sol... + Compiling ./contracts/zombieownership.sol... + Writing artifacts to ./build/contracts +--- + +おめでとう!プロジェクト構成を整え、`truffle-hdwallet-provider`をセットアップできた。さあ、我々のコントラクトをコンパイルするぞ。 + +なぜコンパイルが必要か、聞きたいか? + +_Ethereumの仮想マシン_ はSolidityで書かれたソースコードを直接理解することはできない。従って、コンパイラーを動かし、機械が読める **_bytecode_** に翻訳する必要があるのだ。次に、仮想マシンがバイトコードを実行し、我々のスマートコントラクトが要求するアクションの数々を実行する。 + +バイトコードがどんな感じか興味があるか?少し見てみるか: + +``` +"0x60806040526010600155600154600a0a6002556201518060035566038d7ea4c6800060085560006009556046600a55336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1..." +``` + +この通り、人間どもにとってバイトコードは現実のゾンビと同じくらい理解しがたいものだろう! + +## Solidityのコンパイラーを使用する + +Solidityのコンパイラーの話をするなら、開発者達が用意してくれた気の利いた機能について言及せねばなるまい。 + +`SafeMath`に含まれる`add`関数の定義を次のように修正する: + +``` +function add(uint16 a, uint16 b) internal returns (uint16) { + uint16 c = a + b; + assert(c >= a); + return c; +} +``` + +この関数をコンパイルすると、Solidityのコンパイラーは次のような **_警告_** を発するであろう: + +``` +safemath.sol:110:11: Warning: Function state mutability can be restricted to pure + function add(uint16 a, uint16 b) internal returns (uint16) { + ^ (Relevant source part starts here and spans across multiple lines). +``` + +コンパイラーが言わんとしていることは、この関数はブロックチェーンに読み書きしないから`pure`修飾子を使用せよということだ。 + +なぜ重要かって? + +そう、`pure` や `view`関数はガスを節約できるのであった。関数がブロックチェーンの状態を変更しないのであれば、マイニングする必要がないのだ。言ってしまえば、`pure` や `view`関数は無料で`呼べる`。 + + +## CryptoZombies- The Game + +覚えているか?我々はロジックを`ZombieOwnership.sol`という名のスマートコントラクトに書いたであろう。 + +うーむ…ゲームにとってイケてる名前とは言い難い。 + +幸運にも、名前は問題にならない。継承すれば、同じアクションと機能を持つスマートコントラクトを、任意の名前で作れるからな。 + +さあ、`CryptoZombies`という名前の新たなコントラクトを、`ZombieOwnership.sol`を継承して作成するぞ: + +```solidity +pragma solidity ^0.4.24; + +import "./zombieownership.sol"; + +contract CryptoZombies is ZombieOwnership + { + + } +``` + +次に、スマートコントラクトを全て`./contracts`フォルダーにコピーするぞ。すると、プロジェクトの構成は次のようになるはずだ: + +``` +. +├── contracts + ├── Migrations.sol + ├── CryptoZombies.sol + ├── erc721.sol + ├── ownable.sol + ├── safemath.sol + ├── zombieattack.sol + ├── zombiefactory.sol + ├── zombiefeeding.sol + ├── zombiehelper.sol + ├── zombieownership.sol +├── migrations +└── test +``` + +これで準備は整った。さあ、我々のプロジェクトをコンパイルしようではないか。 + +# さあテストだ + +1. `truffle compile`コマンドを叩け。このコマンドはビルドされた中間生成物を、`./build/contracts`に置いてくれる。 + + > 注: この中間生成物は、スマートコントラクトのバージョン、ABIおよび **Truffle** が使用する内部データで構成された「バイトコード」だ。編集するんじゃないぞ。さもないと **Truffle** が正常に動かなくなるぞ。 diff --git a/jp/10/04.md b/jp/10/04.md new file mode 100644 index 0000000000..ec02e3c3e6 --- /dev/null +++ b/jp/10/04.md @@ -0,0 +1,60 @@ +--- +title: マイグレーション +actions: ['答え合わせ', 'ヒント'] +requireLogin: true +material: + editor: + language: JavaScript + startingCode: + "./contracts/2_crypto_zombies.js": | + var Migrations = artifacts.require("./Migrations.sol"); + module.exports = function(deployer) { + deployer.deploy(Migrations); + }; + answer: | + var CryptoZombies = artifacts.require("./CryptoZombies.sol"); + module.exports = function(deployer) { + deployer.deploy(CryptoZombies); + }; +--- + +通常であれば、 **_Ethereum_** にデプロイする前の時点で、スマートコントラクトをテストしたくなるだろう。Ganacheというツールを使って、 **_Ethereum_** のネットワークをローカル環境に構築することができる。 + +テストは非常に重要ではあるが、その説明には膨大なレッスンが必要となる - だからこのレッスンではデプロイに集中するぞ。テストについて詳しく知りたければ、Testing Smart Contracts with Truffleというレッスンを用意しておるぞ。 + + + +**_Ethereum_** にデプロイするには、 **マイグレーション** と呼ばれるものを作成しなければならない。 + +マイグレーションはJavaScriptで書かれ、 **Truffle** が **_Ethereum_** にデプロイする手助けをしておる。`truffle init`コマンドで作成された`Migrations.sol`という名の特別なコントラクトが、お前がコードに加えた変更を追跡していることに注意せよ。このコントラクトは、変更履歴をオンチェーンに保存しておる。従って、同じコードを2度デプロイすることはできないぞ。 + +## 新しいマイグレーションを作成する + +`truffle init`がすでに作成してくれておるファイルを使うぞ - `./contracts/1_initial_migration.js`だ。 +中身を見てみようではないか: + +```javascript +var Migrations = artifacts.require("./Migrations.sol"); +module.exports = function(deployer) { + deployer.deploy(Migrations); +}; +``` + +ものすごく直感的であろう? + +1行目で `Migrations` コントラクトと対話したいと **Truffle** に伝えている。 + +2行目で`deployer`というオブジェクトをパラメータとして受け取る関数をエクスポートしている。このオブジェクトは、お前(開発者)と **Truffle** のデプロイメントエンジンの間のインターフェースとしての役割をしておる。`deployer`は多数の便利機能を提供しているが、このレッスンでは扱わないぞ。 **Truffle** の能力をもっと知りたければ、終わった後で **Truffle** のドキュメントをチェックするがいい。 + +デプロイに必要なものは揃った。新しいファイル `./contracts/2_crypto_zombies.js` を作成し、`./contracts/1_initial_migration.js` の中身をコピペするぞ。 + +# さあテストだ + +1. `./contracts/2_crypto_zombies.js` を次のように編集せよ: + +```JavaScript +var CryptoZombies = artifacts.require("./CryptoZombies.sol"); +module.exports = function(deployer) { + deployer.deploy(CryptoZombies); +}; +``` diff --git a/jp/10/05.md b/jp/10/05.md new file mode 100644 index 0000000000..5c4767c561 --- /dev/null +++ b/jp/10/05.md @@ -0,0 +1,205 @@ +--- +title: 定義ファイル +actions: ['答え合わせ', 'ヒント'] +requireLogin: true +material: + editor: + language: javascript + startingCode: + "truffle.js": | + + //1. Initialize `truffle-hdwallet-provider` + + // Set your own mnemonic here + const mnemonic = "YOUR_MNEMONIC"; + + // Module exports to make this configuration available to Truffle itself + module.exports = { + // Object with configuration for each network + networks: { + // Configuration for mainnet + mainnet: { + provider: function () { + // Setting the provider with the Infura Mainnet address and Token + return new HDWalletProvider(mnemonic, "https://mainnet.infura.io/v3/YOUR_TOKEN") + }, + network_id: "1" + }, + // Configuration for rinkeby network + rinkeby: { + // Special function to setup the provider + provider: function () { + // Setting the provider with the Infura Rinkeby address and Token + return new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/v3/YOUR_TOKEN") + }, + network_id: //Fill in the `network_id` for the Rinkeby network. + } + } + }; + + answer: | + + const HDWalletProvider = require("truffle-hdwallet-provider"); + + // Set your own mnemonic here + const mnemonic = "YOUR_MNEMONIC"; + + // Module exports to make this configuration available to Truffle itself + module.exports = { + // Object with configuration for each network + networks: { + // Configuration for mainnet + mainnet: { + provider: function () { + // Setting the provider with the Infura Mainnet address and Token + return new HDWalletProvider(mnemonic, "https://mainnet.infura.io/v3/YOUR_TOKEN") + }, + network_id: "1" + }, + // Configuration for rinkeby network + rinkeby: { + // Special function to setup the provider + provider: function () { + // Setting the provider with the Infura Rinkeby address and Token + return new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/v3/YOUR_TOKEN") + }, + // Network id is 4 for Rinkeby + network_id: 4 + } + } + }; +--- + +素晴らしい!ソースコードのコンパイルに成功して、マイグレーションファイルを作ったぞ。 + +デプロイする前にもうひとつだけやるべきことが残っておる。定義ファイルを編集して、 **Truffle** にデプロイ先のネットワークを伝えるのだ。 + +待てよ。 **_Ethereum_** のネットワークは1つだと思っていたが。何か見逃しているんじゃないか? + +## Ethereum Test Networks + +**_Ethereum_** のテスト用ネットワークがいくつか公開されており、メインネットへデプロイする前に、お前のコントラクトを無料でテストさせてくれるのだ(メインネットにコントラクトをデプロイすると、変更できなくなってしまうことを思い出すのだ)。これらのテスト用ネットワークはメインネットとは異なるコンセンサスアルゴリズム(PoAなど)を使用しているから、テストを実行するためのイーサを自由に使えるぞ。 + +このレッスンでは、Rinkebyというネットワークを使うぞ。イーサリアム財団によって作られた、テスト用の公開ネットワークだ。 + +## 定義ファイル truffle.js + +さあ、デフォルトの **Truffle** 定義ファイルを見てみよう: + +```bash +$ cat truffle.js +/* + * NB: since truffle-hdwallet-provider 0.0.5 you must wrap HDWallet providers in a + * function when declaring them. Failure to do so will cause commands to hang. ex: + * + * mainnet: { + * provider: function() { + * return new HDWalletProvider(mnemonic, 'https://mainnet.infura.io/') + * }, + * network_id: '1', + * gas: 4500000, + * gasPrice: 10000000000, + * }, + */ +``` + +ただの空のシェルだ。従って、我々はこのファイルを編集し、Rinkebyとイーサリアムのメインネットにコントラクトをデプロイできるようにしなければならない。 + +### Truffle's HD Wallet Provider + +チャプター2を覚えているか? + +追加で`truffle-hdwallet-provider`というパッケージをインストールし、 **Truffle** が取引に署名できるようにしただろう。 + +定義ファイルを編集して、`HDWalletProvider`を使うようにするぞ。ファイルの先頭に次の行を追加するのだ: + +```JavaScript +const HDWalletProvider = require("truffle-hdwallet-provider"); +``` + +次に、ニーモニックを保存するための変数を作成するぞ: + +```JavaScript +const mnemonic = "onions carrots beans ..."; +``` + +ニーモニックや秘密鍵といった機密情報を定義ファイルに直書きすることは推奨しておらぬぞ。 + +なぜかって? + +定義ファイルはGitHubにプッシュされることが多く、そこでは誰もが見ることができるからだ。攻撃され放題ではないか😱!ニーモニック(または秘密鍵も!)が晒されることを防ぐためには、`.gitignore`に追加されたファイルから読み取るのだ。どうやるかは後で見せてやろう。 + +**今回のケースではシンプルに**、ニーモニックをコピーして変数に格納することとする。 + +### Rinkebyとイーサリアムのメインネット向けにTruffleをセットアップする + +次に、デプロイ先のネットワークを **Truffle** に「知らせる」ために、2つのオブジェクトを作成しなければならない - 1つはRinkeby向け、もう1つは **_イーサリアム_** のメインネット向けだ: + +```JavaScript +networks: { + // Configuration for mainnet + mainnet: { + provider: function () { + // Setting the provider with the Infura Mainnet address and Token + return new HDWalletProvider(mnemonic, "https://mainnet.infura.io/v3/YOUR_TOKEN") + }, + network_id: "1" + }, + // Configuration for rinkeby network + rinkeby: { + // Special function to setup the provider + provider: function () { + // Setting the provider with the Infura Rinkeby address and Token + return new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/v3/YOUR_TOKEN") + }, + // Network id is 4 for Rinkeby + network_id: 4 + } +``` + +> 注: providerはfunctionでラップされていて、必要になるまで初期化されることはない。 + +### まとめ + +さあ、これまでの内容を合体し、定義ファイルがどのようになったか見てみよう: + +```JavaScript +// Initialize HDWalletProvider +const HDWalletProvider = require("truffle-hdwallet-provider"); + +// Set your own mnemonic here +const mnemonic = "YOUR_MNEMONIC"; + +// Module exports to make this configuration available to Truffle itself +module.exports = { + // Object with configuration for each network + networks: { + // Configuration for mainnet + mainnet: { + provider: function () { + // Setting the provider with the Infura Mainnet address and Token + return new HDWalletProvider(mnemonic, "https://mainnet.infura.io/v3/YOUR_TOKEN") + }, + network_id: "1" + }, + // Configuration for rinkeby network + rinkeby: { + // Special function to setup the provider + provider: function () { + // Setting the provider with the Infura Rinkeby address and Token + return new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/v3/YOUR_TOKEN") + }, + // Network id is 4 for Rinkeby + network_id: 4 + } + } +}; +``` + +# さあテストだ + +先に定義ファイルを更新しておいてやった。欠けているピースを埋めるのだ: + +1. ファイルの先頭に、`truffle-hdwallet-provider` を初期化するコードを追加せよ。 + +2. Rinkeby向けの`network_id`を埋めよ。覚えていなければ上のコードスニペットを参照するといい。 diff --git a/jp/10/06.md b/jp/10/06.md new file mode 100644 index 0000000000..19ad7a9733 --- /dev/null +++ b/jp/10/06.md @@ -0,0 +1,57 @@ +--- +title: 我々のスマートコントラクトをデプロイする +actions: ['答え合わせ', 'ヒント'] +requireLogin: true +material: + terminal: + help: + You should probably run `truffle migrate --network rinkeby`. + commands: + "truffle migrate --network rinkeby": + hint: truffle migrate --network rinkeby + output: | + Using network 'rinkeby'. + + Running migration: 1_initial_migration.js + Deploying Migrations... + ... 0xfc34bb95778e4bd53b80c6b705e5df6e753b1accecc38cfd35cb02c0e37ee223 + Migrations: 0x9aba355cd9e68758c7bd9f1e58f911e0479fd29c + Saving successful migration to network... + ... 0x485c7e8096d61a8a1e3efa8d9f5c675b707ca7580ecdb46a307b11146351fc9d + Saving artifacts... + Running migration: 2_crypto_zombies.js + Deploying CryptoZombies... + ... 0xeed64afd64669674d0bc5a68e8c1f86a620d4bd338a652fc42f54353a252d07c + CryptoZombies: 0xccdfdc3d7e002965843d52e610370e8d29d5737f + Saving successful migration to network... + ... 0xdcb1e77f4c1b3982bb15b10bec69bdafbc88fd4ea0b868971e850b02875de68e + Saving artifacts... +--- + +やったな!さっきのは難所だった - 実際のところ、Rinkebyへのデプロイは簡単だ。デプロイする時に、 **Truffle** は **_マイグレーション_** というものに依存するのであったな。 + +# マイグレーション + +マイグレーションは多くの働きをしているように感じたかもしれないが、実際には、スマートコントラクトの状態を変更する方法を **Truffle** に伝えているにすぎない。 + +最初のマイグレーションはスマートコントラクトにデプロイするだけだ。他のマイグレーションもコードの最新バージョンや追加機能、バグ修正をデプロイしているだけだ。 + +一言で言えば、マイグレーションはコードの変更を追跡する便利機能を提供している。 + +複数のコントラクトをデプロイする時は、コントラクト毎に別々のマイグレーションを用意する。マイグレーションは1,2,3, etcの順に実行されるぞ。 + +このレッスンではRinkebyに向けてだけデプロイすることとする。メインネットにデプロイするにはガス代としてお金を支払わなければならないし、デプロイしてしまうとコードを修正できなくなってしまうからだ。従って、まずはRinkebyにデプロイし、コードをテストすることが最善であろう。 + +## イーサを獲得する + +デプロイする前に、お前のアカウントに充分なイーサがなければならない。テスト目的でイーサを獲得する簡単な方法として、 `faucet` というサービスが知られている。Rinkeby上で Authenticated Faucetを動作させることを勧めるぞ。指示に従うと、数分後にはお前のアドレスにいくらかのイーサが入金されるだろう。 + +# さあテストだ + +1. 準備ができたら、Rinkebyにデプロイするぞ。右のターミナルで`truffle migrate --network rinkeby`コマンドを叩け。マイグレーションが実行される順番に注意するんだぞ😉。 + + > 注: `truffle deploy` は `truffle migrate` のエイリアスだ。しかし、我々のコマンドラインのインタプリタは基本的なものだから、`migrate` でないと正しく認識できないぞ。 + +メインネットへのデプロイは難しくないぞ。スマートコントラクトをテストできたら、`truffle migrate --network mainnet`コマンドを叩くだけだ。ガス代の支払いを忘れるな!お前はやれると信じている。 + +全てが順調なら、右と似たようなレスポンスが返されるだろう。 diff --git a/jp/10/07.md b/jp/10/07.md new file mode 100644 index 0000000000..17fd55141b --- /dev/null +++ b/jp/10/07.md @@ -0,0 +1,45 @@ +--- +title: LoomでTruffleを使うぞ! +actions: ['答え合わせ', 'ヒント'] +requireLogin: true +material: + terminal: + help: + You should probably run `npm install loom-truffle-provider`. + commands: + "npm install loom-truffle-provider": + hint: npm install loom-truffle-provider + output: | + + loom-truffle-provider@0.8.0 + added 227 packages from 193 contributors and audited 158456 packages in 50.265s + found 0 vulnerabilities +--- + +あまり何もしてないように感じるかもしれないが、 `CryptoZombies` スマートコントラクトをついにデプロイしたぞ! + +**Truffle** が大いに助けてくれたとはいえ、決して小さな偉業ではない。自分で自分の背中を叩いてやれ。 + + +## LoomのBasechain + +さて、 **_イーサリアム_** 上にDAppsをビルドするなら、気を付けねばならぬことが1つある - メインネットでは、ユーザーは **_取引の度にガス代を支払う_** 必要がある。しかし、ユーザー向けのDAppやゲームには理想的とは言えない。ユーザーエクスペリエンスを台無しにしてしまう。 + +一方、 **_Loom_** 上では、ユーザは高速かつガス代を支払うことなく取引できる。ゲームや金融取引のないアプリにはピッタリだ。 + +つまりお前の **_Loom_** ゾンビたちは素早いゾンビになるということだ! + +それだけではない - **_Loom_** にデプロイする手順は、Rinkebyやイーサリアムのメインネットに対するものと何ら変わりはない。やり方を1つ知っていれば、他に応用できる。 + +次のチャプターでは、 **_Loom_** へのデプロイについて説明するぞ。 + +## loom-truffle-provider + +**_Loom_** では、ビルド、テスト、デプロイに **Truffle** を使用する。楽をするために、 **_provider_** というものを設定して、Truffleが **_Loom_** にデプロイできるようにした。Rinkebyやイーサリアムのメインネットにデプロイする時と同様だ。 + +あまり詳しく説明しないが、providerはWeb3の呼び出しを **_Loom_** と互換性があるようにするブリッジのような機能なのだ。providerの優れた点は、内部を理解せずとも使えることだ。 + +# さあテストだ + +1. `loom-truffle-provider`を `npm` パッケージのように利用できるようにしておいたぞ。インストールするのだ。 + + > 注: 今回はグローバルインストールする必要はない。 diff --git a/jp/10/08.md b/jp/10/08.md new file mode 100644 index 0000000000..c970e73c8d --- /dev/null +++ b/jp/10/08.md @@ -0,0 +1,135 @@ +--- +title: Loomのテストネットにデプロイする +actions: ['答え合わせ', 'ヒント'] +requireLogin: true +material: + editor: + language: javascript + startingCode: + "./truffle.js": | + // Initialize HDWalletProvider + const HDWalletProvider = require("truffle-hdwallet-provider"); + + // 1. Initialize LoomTruffleProvider + + // Set your own mnemonic here + const mnemonic = "YOUR_MNEMONIC"; + + // Module exports to make this configuration available to Truffle itself + module.exports = { + // Object with configuration for each network + networks: { + // Configuration for mainnet + mainnet: { + provider: function () { + // Setting the provider with the Infura Rinkeby address and Token + return new HDWalletProvider(mnemonic, "https://mainnet.infura.io/v3/YOUR_TOKEN") + }, + network_id: "1" + }, + // Configuration for rinkeby network + rinkeby: { + // Special function to setup the provider + provider: function () { + // Setting the provider with the Infura Rinkeby address and Token + return new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/v3/YOUR_TOKEN") + }, + // Network id is 4 for Rinkeby + network_id: 4 + }, + + // 2. Put here the configuration for loom_dapp_chain + + } + }; + answer: | + // Initialize HDWalletProvider + const HDWalletProvider = require("truffle-hdwallet-provider"); + + //Initialize LoomTruffleProvider + const LoomTruffleProvider = require('loom-truffle-provider'); + + // Set your own mnemonic here + const mnemonic = "YOUR_MNEMONIC"; + + // Module exports to make this configuration available to truffle itself + module.exports = { + // Object with configuration for each network + networks: { + // Configuration for mainnet + mainnet: { + provider: function () { + // Setting the provider with the Infura Rinkeby address and Token + return new HDWalletProvider(mnemonic, "https://mainnet.infura.io/v3/YOUR_TOKEN") + }, + network_id: "1" + }, + // Configuration for rinkeby network + rinkeby: { + // Special function to setup the provider + provider: function () { + // Setting the provider with the Infura Rinkeby address and Token + return new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/v3/YOUR_TOKEN") + }, + // Network id is 4 for Rinkeby + network_id: 4 + }, + // Configuration for Loom + loom_testnet: { + provider: function() { + const privateKey = 'YOUR_PRIVATE_KEY' + const chainId = 'extdev-plasma-us1'; + const writeUrl = 'http://extdev-plasma-us1.dappchains.com:80/rpc'; + const readUrl = 'http://extdev-plasma-us1.dappchains.com:80/query'; + return new LoomTruffleProvider(chainId, writeUrl, readUrl, privateKey); + }, + network_id: '9545242630824' + } + } + }; + +--- +このチャプターでは、我々のスマートコントラクトを **_Loom_** のテストネットにデプロイするぞ。だが、デプロイを始める前にやることがある。 + +まず、 **_Loom_** の秘密鍵を作成する。チュートリアルによると、最も簡単な方法は、 **_Loom_** をダウンロードしてインストールする方法だ。 + +次に、秘密鍵を以下のように作る: + +```bash +$./loom genkey -a public_key -k private_key +local address: 0x42F401139048AB106c9e25DCae0Cf4b1Df985c39 +local address base64: QvQBE5BIqxBsniXcrgz0sd+YXDk= +$cat private_key +/i0Qi8e/E+kVEIJLRPV5HJgn0sQBVi88EQw/Mq4ePFD1JGV1Nm14dA446BsPe3ajte3t/tpj7HaHDL84+Ce4Dg== +``` + +> 注: 秘密鍵を公開するなよ!お前に秘密鍵を見せたのは、あくまで雰囲気を掴ませるためだ。 + +## truffle.js を編集する + +まず最初にすべきことは、 `loom-truffle-provider` の初期化だ。構文は `HDWalletProvider` の時に似ているぞ: + +```JavaScript +const LoomTruffleProvider = require('loom-truffle-provider'); +``` + +続いて、チャプター5でやったように、 **_Truffle_** に **_Loom_** のテストネットへデプロイする方法を伝えるぞ。`truffle.js` に次のオブジェクトを追加するんだ: + +```JavaScript +loom_testnet: { + provider: function() { + const privateKey = 'YOUR_PRIVATE_KEY' + const chainId = 'extdev-plasma-us1'; + const writeUrl = 'http://extdev-plasma-us1.dappchains.com:80/rpc'; + const readUrl = 'http://extdev-plasma-us1.dappchains.com:80/query'; + return new LoomTruffleProvider(chainId, writeUrl, readUrl, privateKey); + }, + network_id: '9545242630824' +} +``` + +# さあテストだ + +1. `LoomTruffleProvider` を初期化するコードを追加せよ。 + +2. ファイルの末尾に `loom_testnet` の定義を書け。 diff --git a/jp/10/09.md b/jp/10/09.md new file mode 100644 index 0000000000..b43ec764d3 --- /dev/null +++ b/jp/10/09.md @@ -0,0 +1,70 @@ +--- +title: Loomにデプロイする - 続き +actions: ['答え合わせ', 'ヒント'] +requireLogin: true +material: + terminal: + help: + You should probably run `truffle migrate --network loom_testnet`. + commands: + "truffle migrate --network loom_testnet": + hint: truffle deploy --network loom_testnet + output: | + Starting migrations... + ====================== + > Network name: 'loom_testnet' + > Network id: 9545242630824 + > Block gas limit: 0 + + 1_initial_migration.js + ====================== + + Replacing 'Migrations' + ---------------------- + > transaction hash: 0x526a244695c8d7d0a6e3647a2c07e2d66b1a4fdb0c2623563eaaafca1d84b7d6 + > Blocks: 0 Seconds: 0 + > contract address: 0x98F1F4E2cdfe9BcD505Eb98F4361aFECDEfD8f88 + > account: 0x99A19685cC885e73B3910fb65566d4cb75b7dC70 + > balance: 0 + > gas used: 0 + > gas price: 0 gwei + > value sent: 0 ETH + > total cost: 0 ETH + + + > Saving migration to chain. + > Saving artifacts + ------------------------------------- + > Total cost: 0 ETH + + + 2_crypto_zombies.js + ================= + + Replacing 'CryptoZombies' + ----------------------- + > transaction hash: 0x35f57adc9d96e4cd100c173243a3363b2c9d2a2fceea272914831d2c732f55f9 + > Blocks: 0 Seconds: 0 + > contract address: 0x4c51584414374dD45Ad66F030dB0115d4BcB63a3 + > account: 0x99A19685cC885e73B3910fb65566d4cb75b7dC70 + > balance: 0 + > gas used: 0 + > gas price: 0 gwei + > value sent: 0 ETH + > total cost: 0 ETH + + + > Saving migration to chain. + > Saving artifacts + ------------------------------------- + > Total cost: 0 ETH + +--- + + **_Loom_** のテストネットにデプロイする準備は整った。後はコマンドを1つ叩くだけだ。 + +# さあテストだ + +1. `truffle migrate --network loom_testnet`コマンドを叩いて、出力を見てみろ。 + + よし、シンプルに実現できたな!💪🏻 diff --git a/jp/10/10.md b/jp/10/10.md new file mode 100644 index 0000000000..7887ad16a9 --- /dev/null +++ b/jp/10/10.md @@ -0,0 +1,208 @@ +--- +title: Basechainにデプロイする +actions: ['答え合わせ', 'ヒント'] +requireLogin: true +material: + terminal: + help: + You should probably run `truffle migrate --network basechain`. + commands: + "truffle migrate --network basechain": + hint: truffle migrate --network basechain + output: | + Starting migrations... + ====================== + > Network name: 'basechain' + > Network id: 13654820909954 + > Block gas limit: 0 + + + 1_initial_migration.js + ====================== + + Replacing 'Migrations' + ---------------------- + > transaction hash: 0x5aaab85541e843d54926612e0b4f5faf2d48df8ad461b5f0de571565cabe8dc6 + > Blocks: 0 Seconds: 0 + > contract address: 0xc0eCB06312a20f9435E6Ed3B7eFD7bc0c0865BF2 + > account: 0xE046eB99Cbe99d6760ff01304E25F1dD9116F558 + > balance: 0 + > gas used: 0 + > gas price: 0 gwei + > value sent: 0 ETH + > total cost: 0 ETH + + + > Saving migration to chain. + > Saving artifacts + ------------------------------------- + > Total cost: 0 ETH + + 2_crypto_zombies.js + ================= + + Replacing 'CryptoZombies' + ----------------------- + > transaction hash: 0xeed20de79685ab845e1e848bb871ce87d2fc532d7c87f40b9b25f2bf75b4e3a8 + > Blocks: 0 Seconds: 0 + > contract address: 0xDf2986bbDa42404C8f43A5851aF887B2A3a9CFaB + > account: 0xE046eB99Cbe99d6760ff01304E25F1dD9116F558 + > balance: 0 + > gas used: 0 + > gas price: 0 gwei + > value sent: 0 ETH + > total cost: 0 ETH + + + > Saving migration to chain. + > Saving artifacts + ------------------------------------- + > Total cost: 0 ETH + + + +--- + +やったな! **_Loom_** のテストネットにデプロイできたぞ。次は何をするか思いつくか?🤔 + +そう、正解だ!このチャプターでは、 **_Basechain_** にデプロイするぞ(これがメインネットだ)。 + +このチャプターでやることを要約するとこうだ: + +- 新たな秘密鍵を作成する。 +- 新たな秘密鍵は極めて簡単に作れる。しかしメインネットへのデプロイで伝えた通り、セキュリティにシビアになる時だ。 **Truffle** に安全に秘密鍵を渡す方法を授けてやろう。 +- **_Basechain_** へのデプロイ方法を **Truffle** に伝えるため、定義ファイル `truffle.js` に新たなオブジェクトを追加する。 +- デプロイキーをホワイトリストに追加し、 **_Basechain_** へデプロイできるようにする。 +- 最後に、スマートコントラクトを実際にデプロイする。 + +### 新たな秘密鍵を作成する + +お前はすでに秘密鍵の作成方法を知っているな。しかし、今回はファイル名を変えなければならない: + +```bash +./loom genkey -a mainnet_public_key -k mainnet_private_key +local address: 0x07419790A773Cc6a2840f1c092240922B61eC778 +local address base64: B0GXkKdzzGooQPHAkiQJIrYex3g= +``` + +### Truffleに安全に秘密鍵を渡す + +次にすることは、秘密鍵がGitHubにプッシュされてしまうことを防ぐことだ。 `.gitignore` という新しいファイルを作るぞ: + +```bash +touch .gitignore +``` + +さあ、秘密鍵を保存したファイルを無視するよう、GitHubに「伝え」よう。次のコマンドを叩くのだ: + +```bash +echo mainnet_private_key >> .gitignore +``` + +これで我々の秘密がGitHubにプッシュされる恐れはなくなった。定義ファイル `truffle.js` を編集し、 **Truffle** がこの秘密のファイルから秘密鍵を読み取れるようにしなければならない。 + +手始めにいくつかインポートするぞ: + +```js +const { readFileSync } = require('fs') +const path = require('path') +const { join } = require('path') +``` + +次に、関数を定義したい。この関数はファイルから秘密鍵を読み取り、 `LoomTruffleProvider` のインスタンスを返すぞ: + +```js +function getLoomProviderWithPrivateKey (privateKeyPath, chainId, writeUrl, readUrl) { + const privateKey = readFileSync(privateKeyPath, 'utf-8'); + return new LoomTruffleProvider(chainId, writeUrl, readUrl, privateKey); +} +``` + +簡単だろう? + +### Basechainへのデプロイ方法をTruffleに伝える + +**Truffle** に **_Basechain_** へのデプロイ方法を伝えないとな。新しいオブジェクトを `truffle.js` に追加するぞ! + +```js +basechain: { + provider: function() { + const chainId = 'default'; + const writeUrl = 'http://basechain.dappchains.com/rpc'; + const readUrl = 'http://basechain.dappchains.com/query'; + const privateKeyPath = path.join(__dirname, 'mainnet_private_key'); + const loomTruffleProvider = getLoomProviderWithPrivateKey(privateKeyPath, chainId, writeUrl, readUrl); + return loomTruffleProvider; + }, + network_id: '*' +} +``` + +この時点で、`truffle.js` ファイルは次のような見た目になっているはずだ: + +```js +// Initialize HDWalletProvider +const HDWalletProvider = require("truffle-hdwallet-provider"); + +const { readFileSync } = require('fs') +const path = require('path') +const { join } = require('path') + + +// Set your own mnemonic here +const mnemonic = "YOUR_MNEMONIC"; + +function getLoomProviderWithPrivateKey (privateKeyPath, chainId, writeUrl, readUrl) { + const privateKey = readFileSync(privateKeyPath, 'utf-8'); + return new LoomTruffleProvider(chainId, writeUrl, readUrl, privateKey); +} + +// Module exports to make this configuration available to Truffle itself +module.exports = { + // Object with configuration for each network + networks: { + // Configuration for mainnet + mainnet: { + provider: function () { + // Setting the provider with the Infura Rinkeby address and Token + return new HDWalletProvider(mnemonic, "https://mainnet.infura.io/v3/YOUR_TOKEN") + }, + network_id: "1" + }, + // Configuration for rinkeby network + rinkeby: { + // Special function to setup the provider + provider: function () { + // Setting the provider with the Infura Rinkeby address and Token + return new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/v3/YOUR_TOKEN") + }, + // Network id is 4 for Rinkeby + network_id: 4 + }, + + basechain: { + provider: function() { + const chainId = 'default'; + const writeUrl = 'http://basechain.dappchains.com/rpc'; + const readUrl = 'http://basechain.dappchains.com/query'; + const privateKeyPath = path.join(__dirname, 'mainnet_private_key'); + const loomTruffleProvider = getLoomProviderWithPrivateKey(privateKeyPath, chainId, writeUrl, readUrl); + return loomTruffleProvider; + }, + network_id: '*' + } + } +}; +``` + +### デプロイキーをホワイトリストに追加する + +**_Basechain_** にデプロイする前に、Deploy to Mainnetガイドに従ってデプロイキーをホワイトリストに追加する必要がある。心配はいらないぞ。これをしなければならないことを覚えておけばいい。 + +これら全ての手順を終えたら、 **_Basechain_** にデプロイする準備は完了だ! + +# さあテストだ + +1. `truffle migrate --network basechain`コマンドを叩け。 + +素晴らしい。お前のスマートコントラクトをBasechainにデプロイできたぞ!👏🏻 diff --git a/jp/10/lessoncomplete.md b/jp/10/lessoncomplete.md new file mode 100644 index 0000000000..fbdcbe22ac --- /dev/null +++ b/jp/10/lessoncomplete.md @@ -0,0 +1,20 @@ +--- +title: Lesson Complete! +actions: ['答え合わせ', 'ヒント'] +material: + lessonComplete: 1 +--- + +よくやった!👏🏻👏🏻👏🏻 + +**Truffle** を使ってスマートコントラクトをデプロイする技術を習得できたぞ! + +覚えていて欲しい。**_Loom_** 上に構築することで、高速かつガス代のかからない取引が可能になった。ブロックチェーンゲームやユーザー向けのDAppには完璧な選択だ。加えて、ユーザーはイーサリアムが提供するセキュリティの恩恵を受けられるのだ! + +もう一つ覚えていて欲しいことは、 **_Loom_** へのデプロイとイーサリアムのメインネットへのデプロイが似ていることだ。そしてお前は両方のやり方を知っている。次のプロジェクトでどちらにデプロイするか決める時に注意すればいい😉。 + +とにかく、これは一例に過ぎない - レッスンを分かりやすくするために、我々はいくつかの決定を下したからだ。 + +知識をさらに深めるためには、Developer's Documentationへ行くんだ。 + +Happy coding! diff --git a/jp/index.ts b/jp/index.ts index 695aa04248..e343eac203 100644 --- a/jp/index.ts +++ b/jp/index.ts @@ -115,6 +115,20 @@ import l7_ch9 from './7/09.md' import l7_ch10 from './7/10.md' import l7_ch11 from './7/11.md' import l7_complete from './7/lessoncomplete.md' + +// lesson10 Truffle +import l10_overview from './10/00-overview.md' +import l10_ch1 from './10/01.md' +import l10_ch2 from './10/02.md' +import l10_ch3 from './10/03.md' +import l10_ch4 from './10/04.md' +import l10_ch5 from './10/05.md' +import l10_ch6 from './10/06.md' +import l10_ch7 from './10/07.md' +import l10_ch8 from './10/08.md' +import l10_ch9 from './10/09.md' +import l10_ch10 from './10/10.md' +import l10_complete from './10/lessoncomplete.md' // chapterList is an ordered array of chapters. The order represents the order of the chapters. // chapter index will be 1-based and not zero-based. First chapter is 1 @@ -235,4 +249,18 @@ export default { l7_ch11, l7_complete, ], + 10: [ + l10_overview, + l10_ch1, + l10_ch2, + l10_ch3, + l10_ch4, + l10_ch5, + l10_ch6, + l10_ch7, + l10_ch8, + l10_ch9, + l10_ch10, + l10_complete, + ], }