====== OpenZeppelin で ERC20 トークンの作成 ====== ほぼ OpenZeppelin オフィシャルの[[https://docs.openzeppelin.com/contracts/4.x/erc20|ドキュメント]]通りに ERC20 トークンを実装します。つまり、オリジナルのコインを発行します。 作成したコインは address 間で送金することもできます! それも最後で確認します。 ===== 前提 ===== Truffle と npm をインストールしておいてください。 (参考) [[blockchain:truffleを使ったスマートコントラクト開発|Truffleを使ったスマートコントラクト開発]] ===== プロジェクト作成 ===== > mkdir coin_project > cd coin_project coin_project> truffle init [[blockchain:truffleを使ったスマートコントラクト開発|Truffleを使ったスマートコントラクト開発]] を参考に truffle-config.js の設定をしてください。(どの ethereum ブロックチェーンに接続するか設定する必要があります。) ===== OpenZeppelin のインストール ===== npm を使用して OpenZeppelin をインストールします。 coin_project> npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. See `npm help init` for definitive documentation on these fields and exactly what they do. Use `npm install ` afterwards to install a package and save it as a dependency in the package.json file. Press ^C at any time to quit. package name: (coin_project) version: (1.0.0) description: entry point: (truffle-config.js) test command: git repository: keywords: author: license: (ISC) About to write to C:\Users\miyazato\work\ethereum\coin_project\package.json: { "name": "coin_project", "version": "1.0.0", "description": "", "main": "truffle-config.js", "directories": { "test": "test" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" } Is this OK? (yes) coin_project> npm install --save-dev @openzeppelin/contracts ===== ERC20スマートコントラクト(コイン)の実装 ===== coin_project> truffle create contract OCCToken coin_project> code contracts/OCCToken.sol // contracts/OCCToken.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract OCCToken is ERC20 { constructor(uint256 initialSupply) ERC20("OkinawaComputerCenter", "OCC") { _mint(msg.sender, initialSupply); } } ===== マイグレーション ===== coin_project> truffle create migration OCCToken coin_project> code .\migrations\1651976599_o_c_c_token.js OCCToken スマートコントラクトはデプロイ時にコインの総数(initialSupply)を決定する必要があります。 マイグレーションファイルで initialSupply を10000000枚に指定してみます。 :!: _deployer.deploy の引数は「OCCToken(10000000)」ではなく「OCCToken, 10000000」と記述する必要があります。 const OCCToken = artifacts.require("OCCToken"); module.exports = function(_deployer) { // Use deployer to state migration tasks. _deployer.deploy(OCCToken, 10000000) }; ===== デプロイ(Mint) ===== ERC20 はデプロイ時に新しいToken(コイン)が Mint されます。 実際、OCCToken スマートコントラクトのコンストラクタ(デプロイ時に1度だけ実行される)を見ると「_mint」メソッドを呼び出しています。 coin_project> truffle migrate ===== 実行 ===== OCCToken スマートコントラクトを呼び出して、コインの総数を確認してみます。 coin_project> truffle console truffle(development)> let OCCToken = await OCCToken.deployed(); truffle(development)> OCCToken.totalSupply() BN { negative: 0, words: [ 10000000, <1 empty item> ], length: 1, red: null } truffle(development)> let address = await web3.eth.getAccounts(); truffle(development)> let deployerAddress = address[0]; truffle(development)> OCCToken.balanceOf(deployerAddress); BN { negative: 0, words: [ 10000000, <1 empty item> ], length: 1, red: null } ===== 送金 ===== OCCToken を他のアドレスに送金してみます。 truffle(development)> let receiverAddress = address[1]; undefined truffle(development)> OCCToken.balanceOf(receiverAddress); BN { negative: 0, words: [ 0, <1 empty item> ], length: 1, red: null } truffle(development)> OCCToken.transfer(receiverAddress, 10000); { tx: '0xe0d508b45e2bb412f5c540d96e133a185f5ae4162eb24288d36ee09b7970e825', receipt: { transactionHash: '0xe0d508b45e2bb412f5c540d96e133a185f5ae4162eb24288d36ee09b7970e825', transactionIndex: 0, blockHash: '0xf7c10358304e2a6de5ac1e1f4e13f83df5a785f49a151df39477727b11ddfa86', blockNumber: 5, from: '0x0172ffd2b8ff73056a187fc242af249ac585cc3b', to: '0xaee728a629b239fcf3b56d21067ba36a0a4dbd6c', gasUsed: 51839, cumulativeGasUsed: 51839, contractAddress: null, logs: [ [Object] ], status: true, logsBloom: '0x00000008001010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000002000000000000000010000000000001000000000000000000000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000', rawLogs: [ [Object] ] }, logs: [ { logIndex: 0, transactionIndex: 0, transactionHash: '0xe0d508b45e2bb412f5c540d96e133a185f5ae4162eb24288d36ee09b7970e825', blockHash: '0xf7c10358304e2a6de5ac1e1f4e13f83df5a785f49a151df39477727b11ddfa86', blockNumber: 5, address: '0xaeE728a629b239fCf3B56d21067ba36A0A4dbd6C', type: 'mined', id: 'log_e6c66317', event: 'Transfer', args: [Result] } ] } truffle(development)> OCCToken.balanceOf(deployerAddress); BN { negative: 0, words: [ 9990000, <1 empty item> ], length: 1, red: null } truffle(development)> OCCToken.balanceOf(receiverAddress); BN { negative: 0, words: [ 10000, <1 empty item> ], length: 1, red: null } truffle(development)> ===== まとめ! ===== :!: ここまで来ると、実は ETH の実体もスマートコントラクトであることが分かります! 8-O LOL