TokenをSPAから送金するサンプルを作ってみた
前提
- 執筆者はMacでやっている
- npmは入ってる
-
MetaMask
も入っている
レシピ
- truffleをインストール
- Contractを作る
- RiotでUI作る
- htmlからtruffleを通してContractを操作する
Truffleをインストール
WebインターフェースのDappsを作る為には欠かせない魔法のフレームワーク!
先ずはこいつをインストールしないと話が始まらない
npm install -g truffle
cd [workspace]/
truffle init
Contractを作る
今回は極めてベーシックなERC223
準拠のコインを作る
それ以外の機能は何もなし
contracts/Token.sol
ファイルを作って以下ソースを貼り付け
ワンソースで済ませられるサンプルにするためにSafeMathとか入っていないけど本当は入れたほうが良いよ!
pragma solidity ^0.4.11;
contract ERC223ReceivingContract {
function tokenFallback(address _from, uint _value, bytes _data);
}
contract ERC223 {
string public name = "ERC223";
string public symbol = "TKN";
uint8 public decimals = 18;
uint public totalSupply = 10000000;
mapping(address => uint) balances;
/* ERC20(Etherscan)用送金通知 */
event Transfer(address indexed from, address indexed to, uint value);
/* ERC223用送金通知 */
event Transfer(address from, address to, uint value, bytes data);
/* コンストラクタ */
constructor(string _name, string _symbol, uint8 _decimals, uint256 _totalSupply, uint256 _initialCoin) public {
if (keccak256(_name) != keccak256("")) {
name = _name;
}
if (keccak256(_symbol) != keccak256("")) {
symbol = _symbol;
}
if (_decimals > 0 && _decimals != 18) {
decimals = _decimals;
}
uint __totalSupply = totalSupply;
if (_totalSupply > 0 && _totalSupply != totalSupply) {
__totalSupply = _totalSupply;
}
totalSupply = __totalSupply * 10 ** uint256(decimals);
uint __initialCoin = totalSupply;
if (_initialCoin > 0) {
__initialCoin = _initialCoin;
}
balances[msg.sender] = __initialCoin;
}
/* 送金チェック */
modifier checkTransferEnabled(address _to, uint256 _value) {
// 送金先はOアドレスじゃない
// 送金額が0では無い
// 送金額は残高残高を超えていない
require(
_to != address(0)
&& _value > 0
&& balances[msg.sender] >= _value
);
_;
}
function _transfer(address _to, uint _value, bytes _data) internal checkTransferEnabled(_to, _value) {
uint codeLength;
assembly {
codeLength := extcodesize(_to)
}
balances[msg.sender] = balances[msg.sender] - _value;
balances[_to] = balances[_to] + _value;
if(codeLength > 0) {
ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
receiver.tokenFallback(msg.sender, _value, _data);
}
Transfer(msg.sender, _to, _value);
Transfer(msg.sender, _to, _value, _data);
}
function transfer(address _to, uint _value, bytes _data) {
_transfer(_to, _value, _data);
}
function transfer(address _to, uint _value) {
bytes memory empty;
_transfer(_to, _value, empty);
}
function balanceOf(address _owner) constant returns (uint balance) {
return balances[_owner];
}
}
Remixで動くかテスト
Rinkeby TestNet
にデプロイして動くか確認してみる
無事にデプロイさているか確認
https://rinkeby.etherscan.io/tx/0x4640afd04665d6c75bbd9eee87ab53d6c19d9e03ff52d57713b4a317503c5523
無事されてます(´v`)
知らない人に送金してみる
https://rinkeby.etherscan.io/token/0x99b5df47024ee4f1266e6fc4d20666ed6fbed197
無事に送金されました(´v`)
※トランザクションID(0x4640afd04665d6c75bbd9eee87ab53d6c19d9e03ff52d57713b4a317503c5523)と、Contractアドレス(0x99b5df47024ee4f1266e6fc4d20666ed6fbed197)は後ほど使うのでちゃんとメモしておく!
RiotでUIを作る
Riot
とはズバリ最強のコンポーネント指向JSフレームワークである
信じられないほど簡単にSPAっぽいhtmlが作れるのである
truffle init
した時に出来たindex.html
をひとまず以下の内容で上書き
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="description" content="Sample Riot Dapps"/>
<meta name="robots" content="noindex"/>
<title>Riot with Dapps</title>
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css"/>
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/css-spinning-spinners/1.1.1/load8.css"/>
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"/>
<style>
html, body {
height: 100%;
}
.footer {
position: absolute;
width: 100%;
bottom: 0;
padding: 5px;
background-color: #ddd;
}
.orverlay {
display: none;
position: absolute;
height: 100%;
width: 100%;
z-index: 9999;
background-color: rgba(0, 0, 0, 0.4);
}
.popup-contents {
width: 400px;
height: 200px;
margin: auto;
margin-top: 200px;
padding: 20px;
}
#loader {
z-index: 99999;
}
</style>
</head>
<body>
<div id="loader" class="orverlay loading"></div>
<div id="popup" class="orverlay"></div>
<app class="container">
<navigationbar></navigationbar>
<footer></footer>
<router class="row">
<route path="/">
<holders/>
</route>
<route path="/mypage">
<mypage/>
</route>
</router>
</app>
<!-- Riot tags -->
<section id="riot-tags">
<script type="riot/tag">
<navigationbar>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<!-- sp用 -->
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Riot Dapps</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="#">一覧</a></li>
<li><a href="#mypage">マイページ</a></li>
</ul>
</div>
</div>
</div>
</navigationbar>
</script>
<script type="riot/tag">
<footer class="footer text-right">
2018 © <a href="https://www.digiq.co.jp/" target="_blnak">DigitalQuest,inc.</a>
</footer>
</script>
<script type="riot/tag">
<holders>
<div each="{value, index in list}" class="col-lg-4 col-sm-6 col-xs-12">
<holder index={index} data={value}></holder>
</div>
var testDatas = [];
testDatas[0] = { address: "0xf17f52151ebef6c7334fad080c5704d77216b732", balance: 10000 };
testDatas[1] = { address: "0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef", balance: 20000 };
this.on('mount', function() {
list = testDatas;
riot.update();
});
</holders>
</script>
<script type="riot/tag">
<mypage>
<holder mypage={true} index={index} data={value}/>
var testData = { address: "0x627306090abab3a6e1400e9345bc60c78a8bef57", balance: 100000 };
this.on('mount', function() {
index = 0;
value = testData;
riot.update();
});
</mypage>
</script>
<script type="riot/tag">
<holder>
<div class="bg-info" style="padding: 5px;">
<h4>{opts.data.address}</h4>
<h5>{opts.data.balance}</h5>
<button if={opts.mypage!=true} class="btn btn-success" onclick={onClickTransfer}>送金</button>
</div>
onClickTransfer = function () {
var div = document.createElement("div");
riot.mount(div, "popup-transfer", {"address" : opts.data.address });
$('#popup').html(div);
$('#popup').fadeIn();
};
</holder>
</script>
<script type="riot/tag">
<popup-transfer>
<div class="row bg-info popup-contents">
<p>TO: {opts.address}</p>
<div class="form-group">
<label for="example-email" class="col-md-12">送金数</label>
<div class="col-md-12">
<input type="number" class="form-control form-control-line" onchange="{onChangeForm}" name="coin" ref="coin" value="{coin}" placeholder="1000"/>
<br/>
</div>
<div class="col-sm-12">
<button class="btn btn-success">Transfer</button>
</div>
</div>
</div>
coin = 100;
onChangeForm = function (dom) {
coin = dom.target.value;
};
// ポップアップを閉じる
$('#popup').on('click touchend', function(dom) {
if (!$(dom.target).closest('.popup-contents').length) {
$('#popup').fadeOut().load(function () {
$('#popup').html('');
});
}
});
</popup-transfer>
</script>
</section>
<section id="scripts">
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- Riot -->
<script src="//cdn.jsdelivr.net/npm/riot@3.9/riot+compiler.min.js"></script>
<!-- Riot tag base rooting -->
<script src="//cdn.jsdelivr.net/npm/riot-route@3.1.3/dist/route+tag.min.js"></script>
<script>
$(function() {
$("#loader").fadeIn();
$(window).load(function() {
riot.mount('navigationbar');
riot.mount('footer');
riot.mount('router');
$("#loader").fadeOut();
});
});
</script>
</section>
</body>
</html>
Webサーバを立ち上げて確認してみる
python -m SimpleHTTPServer 8888
おもむろにローカルホストにアクセス
こんな画面になってるかと思います(´v`)
htmlからtruffleを通してContractを操作する
魔法のフレームワーク truffle
を使っているのでhtmlにちょっと細工すればもうContractにアクセス出来ちゃう!
truffleでContractをコンパイルした際に、web3js
(※このあたりを参考https://tomokazu-kozuma.com/how-to-access-ethereums-block-chain-using-web3js/)経由でContractへのアクセスする為のjsonファイルを
なんと自動生成してくれる!
なので、ちょっいじって読み込めばもう使えてしまうのである
truffle devlop
truffle(develop)> migrate
すると・・・
build/contracts/ERC223.json
と言うファイルが出来ていると思われる
このjsonファイルがhtmlからweb3js経由でContractを呼び出すキモになるファイル
しかし、このままだとローカルでしか動作しないので、先程のRinkeby TestNet
にデプロイしたContractのネットワークとアドレス情報を書き加える
ERC223.json
の7980行目付近
"networks": {},
ここを
"networks": {
"4": {
"events": {},
"links": {},
"address": "0x99b5df47024ee4f1266e6fc4d20666ed6fbed197",
"transactionHash": "0x4640afd04665d6c75bbd9eee87ab53d6c19d9e03ff52d57713b4a317503c5523"
}
},
こう変えます。
"4"
の部分は固定
networks:4はRinkeby TestNet
のネットワークIDになっている
addressには上でメモしたContractアドレスを
transactionHashには上でメモしたトランザクションIDを
それぞれ入れる
あと、136行目からの
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
この部分はWebインターフェースからは不要なので削除
コレでContractのjsonの準備は終わり
ここまで来たらあとはhtmlを治すだけ!
htmlにweb3jsとtrufflejsの読み込みを加える
・・・
<!-- Riot tag base rooting -->
<script src="//cdn.jsdelivr.net/npm/riot-route@3.1.3/dist/route+tag.min.js"></script>
<!-- web3jsとtrufflejsの読み込みを追加 -->
<script src="//cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/truffle-contract@3.0.5/dist/truffle-contract.min.js"></script>
<script>
・・・
Cntractを操作するApp
クラスを定義
・・・
<script>
App = {
web3Provider: null,
contracts: {},
dev: false,
contractJSONPath: '',
ganache: false,
init: function(_contractJSONPath, _ganache = false) {
contractJSONPath = _contractJSONPath;
ganache = _ganache;
return App.initWeb3();
},
initWeb3: function() {
if (typeof web3 !== 'undefined') {
App.web3Provider = web3.currentProvider;
}
else {
if (false === (navigator.userAgent.indexOf('Chrome') > 0 && document.location.href.indexOf('localhost:3000') > -1)) {
// web3ナシでスタート確定
App.dev = true;
riot.mount('navigationbar');
riot.mount('footer');
riot.mount('router');
$("#loader").fadeOut();
return;
}
if (ganache) {
// this is Ganache develop network
App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
}
else {
// this is truffle develop network
App.web3Provider = new Web3.providers.HttpProvider('http://localhost:9545');
}
}
web3 = new Web3(App.web3Provider);
return App.initContract();
},
initContract: function() {
$.getJSON(contractJSONPath, function(Artifact) {
App.contracts.contract = TruffleContract(Artifact);
App.contracts.contract.setProvider(App.web3Provider);
try {
riot.mount('navigationbar');
riot.mount('footer');
riot.mount('router');
$("#loader").fadeOut();
}
catch (err) {
App.error(err);
}
return;
}).error(function(jqXHR, textStatus, err) {
jqXHR.message = 'コントラクト見つかりません。';
App.error(jqXHR);
});
return App.bindEvents();
},
bindEvents: function() {
//$(document).on('click', '#registerBtn', App.handleRegister);
},
success: function(result, callback, errmessage = '取引エラーが発生した為、取引を完了出来ませんでした。') {
console.log(result);
if ('undefined' != typeof result.receipt && 'undefined' != typeof result.receipt.transactionHash && 0 == result.receipt.transactionHash.indexOf('0x')) {
// 正常
if ('undefined' != typeof callback) {
return callback(result);
}
alert('正常に取引が完了しました。');
return;
}
alert(errmessage);
},
error: function(err) {
if (-1 < err.message.indexOf('property') && -1 < err.message.indexOf('route') && -1 < err.message.indexOf('null')) {
// このエラーは一旦無視
return;
}
console.log(err);
message = err.message;
if (-1 < err.message.indexOf('Invalid') && -1 < err.message.indexOf('JSON')) {
message = 'コントラクトと接続出来ませんでした。';
}
else if (-1 < err.message.indexOf('wasn') && -1 < err.message.indexOf('t processed in')) {
message = 'この取引は処理に時間が掛かっています。\n暫く待ってから取引結果を確認して下さい。';
err = null;
}
else if (-1 < err.message.indexOf('User') && -1 < err.message.indexOf('denied') && -1 < err.message.indexOf('transaction')) {
message = 'コントラクトの実行を中止しました。';
err = null;
}
alert(message);
$("#loader").fadeOut();
},
transfer: function(address, coin, callback) {
if (App.dev) {
// テストデータの返却
callback(true);
return;
}
web3.eth.getAccounts(function(error, accounts) {
if (error) {
console.log(error);
}
var account = accounts[0];
if ('undefined' == typeof account) {
App.error({message: 'コントラクトに参加中のアドレスが見つかりませんでした。'});
return;
}
if (account == address) {
App.error({message: '自分自身に対してこの操作は出来ません。'});
return;
}
coin = parseInt(coin + '000000000000000000');
App.contracts.contract.deployed().then(function(instance) {
return instance.transfer(address, coin, '0xad', {from: account});
}).then(function(result) {
App.success(result, callback);
}).catch(function(err) {
App.error(err);
});
});
},
};
$(function() {
$("#loader").fadeIn();
・・・
App
クラスをhtmlのロードで初期化するように書き換え
・・・
$(function() {
$("#loader").fadeIn();
$(window).load(function() {
App.init('./build/contracts/ERC223.json');
});
});
</script>
・・・
初期化時に先程のERC223.json
を渡してContractの操作をJSから行えるようにしている!
※このあたりの作りはフレームワークのもお作法による物のでは無いので、自分で使いやすいようにアレンジして行ったら良いです
最後に、UIボタンからApp.transfer
を実行する部分を追記して終わり!
<script type="riot/tag">
<popup-transfer>
・・・
// 送金アクション
transfer = function () {
$("#loader").fadeIn();
App.transfer(opts.address, coin, function(result) {
$("#loader").fadeOut();
alert(opts.address + ' へ ' + coin + ' 枚送金しました。');
});
};
</popup-transfer>
・・・
はい、完成!!
(※最終的なソースはページの最後に書いてます)
実際に動かしてみる・・・
無事にMetaMask
起動!
SUBMITすると・・・
https://rinkeby.etherscan.io/token/0x99b5df47024ee4f1266e6fc4d20666ed6fbed197
ちゃんと送金されてHolderが増える! (´v`)v
まとめ
以上、かなーーりハショリつつでしたが、Dappsの作り方のご紹介でした
ちなみ、本番のネットワークはID「1」なので
"networks": {
"4": {
を
"networks": {
"1": {
と変えて、Remixでデプロイ先をMainNetに向けてれば本番環境で動きます (´v`)d
是非是非お試しあれ!
m(_ _)mお粗末でした
おまけ
最終html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="description" content="Sample Riot Dapps"/>
<meta name="robots" content="noindex"/>
<title>Riot with Dapps</title>
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css"/>
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/css-spinning-spinners/1.1.1/load8.css"/>
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"/>
<style>
html, body {
height: 100%;
}
.footer {
position: absolute;
width: 100%;
bottom: 0;
padding: 5px;
background-color: #ddd;
}
.orverlay {
display: none;
position: absolute;
height: 100%;
width: 100%;
z-index: 9999;
background-color: rgba(0, 0, 0, 0.4);
}
.popup-contents {
width: 400px;
height: 200px;
margin: auto;
margin-top: 200px;
padding: 20px;
}
#loader {
z-index: 99999;
}
</style>
</head>
<body>
<div id="loader" class="orverlay loading"></div>
<div id="popup" class="orverlay"></div>
<app class="container">
<navigationbar></navigationbar>
<footer></footer>
<router class="row">
<route path="/">
<holders/>
</route>
<route path="/mypage">
<mypage/>
</route>
</router>
</app>
<!-- Riot tags -->
<section id="riot-tags">
<script type="riot/tag">
<navigationbar>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<!-- sp用 -->
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Riot Dapps</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="#">一覧</a></li>
<li><a href="#mypage">マイページ</a></li>
</ul>
</div>
</div>
</div>
</navigationbar>
</script>
<script type="riot/tag">
<footer class="footer text-right">
2018 © <a href="https://www.digiq.co.jp/" target="_blnak">DigitalQuest,inc.</a>
</footer>
</script>
<script type="riot/tag">
<holders>
<div each="{value, index in list}" class="col-lg-4 col-sm-6 col-xs-12">
<holder index={index} data={value}></holder>
</div>
var testDatas = [];
testDatas[0] = { address: "0xf17f52151ebef6c7334fad080c5704d77216b732", balance: 10000 };
testDatas[1] = { address: "0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef", balance: 20000 };
this.on('mount', function() {
list = testDatas;
riot.update();
});
</holders>
</script>
<script type="riot/tag">
<mypage>
<holder mypage={true} index={index} data={value}/>
var testData = { address: "0x627306090abab3a6e1400e9345bc60c78a8bef57", balance: 100000 };
this.on('mount', function() {
index = 0;
value = testData;
riot.update();
});
</mypage>
</script>
<script type="riot/tag">
<holder>
<div class="bg-info" style="padding: 5px;">
<h4>{opts.data.address}</h4>
<h5>{opts.data.balance}</h5>
<button if={opts.mypage!=true} class="btn btn-success" onclick={onClickTransfer}>送金</button>
</div>
onClickTransfer = function () {
var div = document.createElement("div");
riot.mount(div, "popup-transfer", {"address" : opts.data.address });
$('#popup').html(div);
$('#popup').fadeIn();
};
</holder>
</script>
<script type="riot/tag">
<popup-transfer>
<div class="row bg-info popup-contents">
<p>TO: {opts.address}</p>
<div class="form-group">
<label for="example-email" class="col-md-12">送金数</label>
<div class="col-md-12">
<input type="number" class="form-control form-control-line" onchange="{onChangeForm}" name="coin" ref="coin" value="{coin}" placeholder="1000"/>
<br/>
</div>
<div class="col-sm-12">
<button class="btn btn-success" onclick={transfer}>Transfer</button>
</div>
</div>
</div>
coin = 100;
onChangeForm = function (dom) {
coin = dom.target.value;
};
// ポップアップを閉じる
$('#popup').on('click touchend', function(dom) {
if (!$(dom.target).closest('.popup-contents').length) {
$('#popup').fadeOut().load(function () {
$('#popup').html('');
});
}
});
// 送金アクション
transfer = function () {
$("#loader").fadeIn();
App.transfer(opts.address, parseInt(coin + '000000000000000000'), function(result) {
$("#loader").fadeOut();
alert(opts.address + ' へ ' + coin + ' 枚送金しました。');
});
};
</popup-transfer>
</script>
</section>
<section id="scripts">
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- Riot -->
<script src="//cdn.jsdelivr.net/npm/riot@3.9/riot+compiler.min.js"></script>
<!-- Riot tag base rooting -->
<script src="//cdn.jsdelivr.net/npm/riot-route@3.1.3/dist/route+tag.min.js"></script>
<!-- Truffle -->
<script src="//cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/truffle-contract@3.0.5/dist/truffle-contract.min.js"></script>
<script>
App = {
web3Provider: null,
contracts: {},
dev: false,
contractJSONPath: '',
ganache: false,
init: function(_contractJSONPath, _ganache = false) {
contractJSONPath = _contractJSONPath;
ganache = _ganache;
return App.initWeb3();
},
initWeb3: function() {
if (typeof web3 !== 'undefined') {
App.web3Provider = web3.currentProvider;
}
else {
if (false === (navigator.userAgent.indexOf('Chrome') > 0 && document.location.href.indexOf('localhost:3000') > -1)) {
// web3ナシでスタート確定
App.dev = true;
riot.mount('navigationbar');
riot.mount('footer');
riot.mount('router');
$("#loader").fadeOut();
return;
}
if (ganache) {
// this is Ganache develop network
App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
}
else {
// this is truffle develop network
App.web3Provider = new Web3.providers.HttpProvider('http://localhost:9545');
}
}
web3 = new Web3(App.web3Provider);
return App.initContract();
},
initContract: function() {
$.getJSON(contractJSONPath, function(Artifact) {
App.contracts.contract = TruffleContract(Artifact);
App.contracts.contract.setProvider(App.web3Provider);
try {
riot.mount('navigationbar');
riot.mount('footer');
riot.mount('router');
$("#loader").fadeOut();
}
catch (err) {
App.error(err);
}
return;
}).error(function(jqXHR, textStatus, err) {
jqXHR.message = 'コントラクト見つかりません。';
App.error(jqXHR);
});
return App.bindEvents();
},
bindEvents: function() {
//$(document).on('click', '#registerBtn', App.handleRegister);
},
success: function(result, callback, errmessage = '取引エラーが発生した為、取引を完了出来ませんでした。') {
console.log(result);
if ('undefined' != typeof result.receipt && 'undefined' != typeof result.receipt.transactionHash && 0 == result.receipt.transactionHash.indexOf('0x')) {
// 正常
if ('undefined' != typeof callback) {
return callback(result);
}
alert('正常に取引が完了しました。');
return;
}
alert(errmessage);
},
error: function(err) {
if (-1 < err.message.indexOf('property') && -1 < err.message.indexOf('route') && -1 < err.message.indexOf('null')) {
// このエラーは一旦無視
return;
}
console.log(err);
message = err.message;
if (-1 < err.message.indexOf('Invalid') && -1 < err.message.indexOf('JSON')) {
message = 'コントラクトと接続出来ませんでした。';
}
else if (-1 < err.message.indexOf('wasn') && -1 < err.message.indexOf('t processed in')) {
message = 'この取引は処理に時間が掛かっています。\n暫く待ってから取引結果を確認して下さい。';
err = null;
}
else if (-1 < err.message.indexOf('User') && -1 < err.message.indexOf('denied') && -1 < err.message.indexOf('transaction')) {
message = 'コントラクトの実行を中止しました。';
err = null;
}
alert(message);
$("#loader").fadeOut();
},
transfer: function(address, coin, callback) {
if (App.dev) {
// テストデータの返却
callback(true);
return;
}
web3.eth.getAccounts(function(error, accounts) {
if (error) {
console.log(error);
}
var account = accounts[0];
if ('undefined' == typeof account) {
App.error({message: 'コントラクトに参加中のアドレスが見つかりませんでした。'});
return;
}
if (account == address) {
App.error({message: '自分自身に対してこの操作は出来ません。'});
return;
}
coin = parseInt(coin + '000000000000000000');
App.contracts.contract.deployed().then(function(instance) {
return instance.transfer(address, coin, '0xad', {from: account});
}).then(function(result) {
App.success(result, callback);
}).catch(function(err) {
App.error(err);
});
});
},
};
$(function() {
$("#loader").fadeIn();
$(window).load(function() {
App.init('./build/contracts/ERC223.json');
});
});
</script>
</section>
</body>
</html>