#はじめに
Browser-solidityなどコントラクトを書く手段はいくつかありますが、
コードの管理や、コンパイル、デプロイなど、都度異なる方法でやっていると雑多になってしまうので、TruffleというEthereum開発フレームワークを使って行きます。
#チュートリアル
truffleframeworkにはpet-shopを作るチュートリアルが公開されています。
http://truffleframework.com/tutorials/pet-shop#interacting-with-the-dapp-in-a-browser
#流れ
コントラクトの作成
$ truffle create contract コントラクト名
↓
コンパイル
$ truffle compile
Solidityで書かれたコードをEVM(EthereumVirtualMachine)で実行するためにバイトコードに変換する
↓
デプロイ
$ truffle migration
testnetなど環境を選択した上で、ブロックチェーンネットワークへdeployする
↓
テスト
$ truffle test
#MyToken(独自トークン)を作る事例
##1.Truffleをインストール
$ npm install -g truffle
//フォルダ作成
$ mkdir ~/battle-coin
$ cd ~/battle-coin
//初期化
$ truffle init
npm init -f
//OpenZeppelinライブラリを入れる
npm i zeppelin-solidity --save
##2.Tokenの作成
$ truffle create contract MyToken (<- contracts/MyToken.solが作られる)
$ vim contracts/MyToken.sol
MyToken.sol
pragma solidity ^0.4.17;
import 'zeppelin-solidity/contracts/token/StandardToken.sol';
contract MyToken is StandardToken {
string public constant name = "BattleCoin";
string public constant symbol = "BAC";
uint256 public constant decimals = 0;
uint256 public constant INITIAL_SUPPLY = 100000000;
function MyToken() {
totalSupply = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
}
}
$ touch migrations/2_deploy_battle_coin.js
migrations/2_deploy_battle_coin.js
const MyToken2 = artifacts.require("./MyToken.sol");
module.exports = function(deployer) {
//deployer.deploy(MyToken);
let initialSupply = 1000000
let maxSupply = 100000000
deployer.deploy(MyToken, initialSupply, maxSupply, {
gas: 2000000
})
};
##3.deployする
truffle.js
var HDWalletProvider = require("truffle-hdwallet-provider");
var mnemonic = "traction unplanned litigate game shrank preppy disorder gumdrop ..........";
var accessToken = "aaa";
module.exports = {
networks: {
ropsten: {
provider: function() {
return new HDWalletProvider(
mnemonic,
"https://ropsten.infura.io/" + accessToken
);
},
network_id: 3,
gas: 500000
}
}
};
//truffle-hdwallet-providerを入れる
npm install truffle-hdwallet-provider
//接続する
truffle console --network ropsten
//アカウントのアドレスを確認する
truffle(ropsten)> web3.eth.getAccounts(function(err, res){console.log(res)})
//必要なら開発用のetherを入れておく
$ curl -X POST -H "Content-Type: application/json" -d '{"toWhom":"0x76487f6311c70d08c052a113b5c26436ce837b8c"}' https://ropsten.faucet.b9lab.com/tap
//確認
https://ropsten.etherscan.io/address/0x76487f6311c70d08c052a113b5c26436ce837b8c
//migrateする
truffle(ropsten)>migrate
//確認する
truffle(develop)> myToken = MyToken.at(MyToken.address)
truffle(develop)> myToken.name()
truffle(develop)> myToken.totalSupply()
//送金する
myToken.transfer("0xC2b10c8727E8EDBf03Dd9EC69845D99bBDfAB11a", 23)
##4.独自tokenをMyEtherWalletに送金して管理する
##5.おまけ(Web3.jsを使って、作成したtokenをやり取りする)
###token残高のsample
balance.js
#!/usr/bin/env node
var Web3 = require('web3');
var web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider('https://ropsten.infura.io/'));
web3.eth.defaultAccount=web3.eth.accounts[0]
//Contract details (bytecode, interface etc.)のInterfaceをabiとして貼り付ける
var abi = [{"constant": true,"inputs": [],"name": "name","outputs": [{"name": "","type": "string"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": false,"inputs": [{"name": "_spender","type": "address"},{"name": "_value","type": "uint256"}],"name": "approve","outputs": [{"name": "","type": "bool"}],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": true,"inputs": [],"name": "totalSupply","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": false,"inputs": [{"name": "_from","type": "address"},{"name": "_to","type": "address"},{"name": "_value","type": "uint256"}],"name": "transferFrom","outputs": [{"name": "","type": "bool"}],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": true,"inputs": [],"name": "INITIAL_SUPPLY","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "decimals","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": false,"inputs": [{"name": "_spender","type": "address"},{"name": "_subtractedValue","type": "uint256"}],"name": "decreaseApproval","outputs": [{"name": "","type": "bool"}],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": true,"inputs": [{"name": "_owner","type": "address"}],"name": "balanceOf","outputs": [{"name": "balance","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": true,"inputs": [],"name": "symbol","outputs": [{"name": "","type": "string"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": false,"inputs": [{"name": "_to","type": "address"},{"name": "_value","type": "uint256"}],"name": "transfer","outputs": [{"name": "","type": "bool"}],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": false,"inputs": [{"name": "_spender","type": "address"},{"name": "_addedValue","type": "uint256"}],"name": "increaseApproval","outputs": [{"name": "","type": "bool"}],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": true,"inputs": [{"name": "_owner","type": "address"},{"name": "_spender","type": "address"}],"name": "allowance","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"inputs": [],"payable": false,"stateMutability": "nonpayable","type": "constructor"},{"anonymous": false,"inputs": [{"indexed": true,"name": "owner","type": "address"},{"indexed": true,"name": "spender","type": "address"},{"indexed": false,"name": "value","type": "uint256"}],"name": "Approval","type": "event"},{"anonymous": false,"inputs": [{"indexed": true,"name": "from","type": "address"},{"indexed": true,"name": "to","type": "address"},{"indexed": false,"name": "value","type": "uint256"}],"name": "Transfer","type": "event"}];
//var _balance = web3.eth.contract(abi).at("コントラクトのアドレス").balanceOf("残高確認用のアドレス");
var _balance = web3.eth.contract(abi).at("0x4B5361044c2AD394F4E6696A1315Ac5Bc221a095").balanceOf("0x76487f6311c70d08c052a113b5c26436ce837b8c");
console.log(_balance);
###token送付するsample
send_token.js
getTokenContractInstance: function () {
const tokenAddress = "---tokenのアドレス---";
const contractABI = [---ABIの中身---]
const tokenContract = web3.eth.contract(contractABI);
return tokenContract.at(tokenAddress);
},
sendToken: async function (toAddress, amount, gasLimit) {
const payload = getTokenContractInstance().transfer.getData(toAddress, amount);
const newTx = await constructNewTx(tokenAddress, 0, gasLimit, payload, Chains.Ropsten);
submitRawTxToBlockchain(newTx, (result, error) => {
if ((error)) {
console.log(error)
} else {
console.log(result)
}
});
},
constructNewTx: async function (toAddress, amount, gasLimit, data, chainId) {
const transactionCount = await getTransactionCount(toAddress);
const gasPrice = await getGasPrice();
return new Promise((resolve, reject) => {
web3.eth.getTransactionCount(walletAddress, (error, result) => {
if (error) {
reject(error)
} else {
const newTxParams = {
nonce: "0x" + result,
gasPrice: "0x" + gasPrice,
gasLimit: "0x" + Number(gasLimit).toString(16),
to: toAddress,
value: "0x" + Number(web3.toWei(amount, "ether")).toString(16),
data: data,
chainId: chainId
};
resolve(newTxParams)
}
})
});
},
getTransactionCount: function (address) {
return new Promise((resolve, reject) => {
web3.eth.getTransactionCount(address, (error, result) => {
if (error) {
reject(error)
} else {
resolve(result.toString('16'))
}
})
});
},
getGasPrice: function() {
return new Promise((resolve, reject) => {
web3.eth.getGasPrice((error, result) => {
if (error) {
reject(error)
} else {
resolve(result.toString('16'))
}
})
})
},