/
index.html
326 lines (293 loc) · 13.9 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="CACHE-CONTROL" content="NO-CACHE">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.3.0/milligram.min.css">
<title>한반도의 평화와 번영, 통일을 위한 판문점 선언</title>
<style>
body {margin-left:50px;}
#storedData {font-size:300%; margin-right:10px;}
#newValue {width: 200px; margin-right:10px; text-align:right;}
pre {padding: 20px; box-sizing: border-box; max-height:300px; overflow-y: auto; margin-top: 0px;}
pre {white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap;
white-space: -o-pre-wrap; word-wrap: break-word;}
.comments {list-style-type: none;}
</style>
</head>
<body>
<h3>한반도의 평화와 번영, 통일을 위한 판문점 선언</h3>
<p>2018년 4월 27일 남북정상 회담의 결과로 발표된 판문점 선언 전문을 이더리움 블록체인에 영구불변하게 보존하고 이를 지지하고 성원함으로써 하루라도 빨리 남북통일이 되는 날을
바라는 모든 국민들의 염원을 담기위해 이 스마트컨트랙을 만들었습니다.</p>
<p>이 사이트는 메타마스크가 인스톨되거나 이더리움이 지원되는 브라우저에서 정상적으로 작동합니다. </p>
<p>
<button style="display:none;" id="btnConnect" onclick="connectAccount()">이더리움 연결하기</button>
<!-- a target="_blank" href='http://www.chaintalk.io/archive/ethereum_guide/2'>메타마스크 깔기</a><br>
<a target="_blank" href='https://brave.com/'>Brave 브라우저 받기</a -->
</p>
<img src="aftersigned.jpeg" style="width: 600px;">
<ul>
<li>이더리움 네트워크: <span id="networkName"></span></li>
<li>컨트랙트 주소: <span id="contractAddr"></span></li>
<li>내 어카운트 주소: <span id="accountAddr"></span></li>
<li><button onclick="getDecContent()">선언전문 불러오기</button>
<pre id="decContent">한반도의 평화와 번영, 통일을 위한 판문점 선언</pre>
</li>
<li>새댓글달기:<br>
<textarea id="newComment" rows="2" cols="30" style="width:600px;"></textarea><br>
<button onclick="saveComment()">댓글저장</button>
<div id="newTxid"></div>
</li>
</ul>
<h4>나의 댓글</h4>
<ul id="myComments" class="comments">
</ul>
<h4>주소로 댓글찾기</h4>
<input type="text" name="targetAddr" id="targetAddr" style="width:350px;"><button onclick="getCommentsByAddr()">댓글찾기</button>
<ul id="targetComments" class="comments">
</ul>
<h4>전체 댓글</h4>
총 댓글 갯수: <span id="numComments"></span> <br>
<ul id="allComments" class="comments">
</ul>
<h4>컨트랙트 소스</h4>
<script src="https://gist.github.com/atomrigs/59230a518936620ea1b0e8234fba2000.js"></script>
<H4>HTML 소스</h4>
<a href="https://github.com/panmunjom/panmunjom.github.io/blob/master/index.html">https://github.com/panmunjom/panmunjom.github.io/blob/master/index.html</a><br><br>
<p>by Atomrigs © 2018 </p>
<script src="https://cdn.jsdelivr.net/npm/web3@1.2.11/dist/web3.min.js"></script>
<!-- script src="https://unpkg.com/@metamask/detect-provider/dist/detect-provider.min.js"></script -->
<!-- script src="https://cdn.ethers.io/lib/ethers-5.0.umd.min.js"></script -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/tingle/0.15.3/tingle.min.js" integrity="sha512-plGUER9JkeEWPPqQBE4sdLqBoQug5Ap+BCGMc7bJ8BXkm+VVj6QzkpBz5Yv2yPkkq+cqg9IpkBaGCas6uDbW8g==" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tingle/0.15.3/tingle.min.css" integrity="sha512-j1u8eUJ4f23xPPxwOrLUPQaCD2dwzNqqmDDcWS4deWsMv2ohLqmXXuP3hU7g8TyzbMSakP/mMqoNBYWj8AEIFg==" crossorigin="anonymous" />
<script>
var abi = [{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":false,"name":"comment","type":"string"},{"indexed":false,"name":"timestamp","type":"uint256"},{"indexed":false,"name":"count","type":"uint256"}],"name":"Commented","type":"event"},{"constant":false,"inputs":[{"name":"comment","type":"string"}],"name":"makeComment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"blockByCounter","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"content","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"numComments","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}];
var contractAddress;
var declaration;
var myAddr;
var chainId;
var maxComments = 200;
var networkList = {
1: "메인넷",
3: "Ropsten 테스트넷",
4: "Rinkeby 테스트넷",
5: "Goerli 테스트넷",
42: "Kovan 테스트넷",
1337: "Gnache 로컬넷"
};
var modal = new tingle.modal();
window.addEventListener('load', function() {
if (typeof window.ethereum !== 'undefined') {
window.web3 = new Web3(window.ethereum);
} else if (typeof web3 !== 'undefined') {
window.web3 = new Web3(web3.currentProvider);
} else {
window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}
if (typeof window.web3 !== 'undefined') {
startApp();
} else {
alert("You need to install dapp browser first to use this site!")
}
});
var commentHashes = [];
var allList = getElem('allComments');
var myList = getElem('myComments');
async function startApp() {
try {
removeAllChildNodes(allList);
removeAllChildNodes(myList);
chainId = parseInt(await ethereum.request({method: 'eth_chainId'}));
getElem('networkName').innerText = networkList[chainId];
getAccount();
} catch(err) {console.log(err);}
}
async function getAccount() {
try {
var accounts = await ethereum.request({method: 'eth_accounts'});
if (accounts.length > 0) {
myAddr = web3.utils.toChecksumAddress(accounts[0]);
getElem('accountAddr').innerHTML = getLink(myAddr);
getContract();
} else {
getElem("btnConnect").style.display = "block";
console.log("No ethereum account is available!")
}
} catch(err) {
console.log(err);}
}
async function getContract() {
try {
if (chainId==1) contractAddress = '0xdc7c743110Ec689d82f050302319AE27aF84f8fa';
else if (chainId==3) contractAddress = '0x1Fc92380ee35b6eD84Ea87F47e0805AA953a3f40';
else if (chainId==4) contractAddress = '0x31D9BC105a7eE27c7b78Ba3758Cf7B5D79ccA06E';
else if (chainId==5) contractAddress = '0x4E3d5BF9e8C9C3ff6950418C20B67A38b98a932E';
else if (chainId==42) contractAddress = '0xfCaBE7Eae959Cc166719D0f4562A83850472cb3d';
else if (chainId==1337) contractAddress = '0xeF6c877d3447CDF3C4177d3802A13AF6Fbd59bcF';
else console.log("not supported chain " + chainId);
getElem('contractAddr').innerHTML = getLink(contractAddress);
declaration = new web3.eth.Contract(abi, contractAddress);
await getComments();
watchChainAccount();
} catch(err) {console.log(err);}
}
function watchChainAccount() {
web3.currentProvider.on("accountsChanged", (accounts) => {
startApp();
modal.setContent("<p>어카운트가 변경되었습니다!</p><button onclick='location.reload()'>다시 로딩하기</button>");
modal.open();
});
web3.currentProvider.on("chainChanged", (chainId) => {
startApp();
modal.setContent("<p>네트워크(체인)이 변경되었습니다!</p><button onclick='location.reload()'>다시 로딩하기</button>");
modal.open();
});
web3.currentProvider.on("connect", (connectInfo) => {
//startApp();
console.log(connectInfo);
modal.setContent("<p>Etheruem Provider가 연결되었습니다.</p>");
modal.open();
});
web3.currentProvider.on("disconnect", (error) => {
//startApp();
console.log(error);
modal.setContent("<p>Ethereum Provider가 연결이 끊어졌습니다.</p><button onclick='location.reload()'>다시 로딩하기</button>");
modal.open();
});
}
function connectAccount() {
ethereum
.request({method: 'eth_requestAccounts'})
.then((accounts) => {
myAddr = accounts[0];
getElem('accountAddr').innerHTML = getLink(myAddr);
getElem("btnConnect").style.display = "none";
getContract();
})
.catch((err) => {
if (err.code === 4001) {
// EIP-1193 userRejectedRequest error
// If this happens, the user rejected the connection request.
console.log('Please connect to Your wallet!');
} else {
console.error(err);
}
});
}
function getDecContent() {
declaration.methods.content().call()
.then((r) => {
getElem("decContent").innerHTML=r;
})
}
function saveComment() {
var newComment = getElem('newComment').value;
declaration.methods.makeComment(newComment).send({from: myAddr, gasPrice: 10000000000})
.on('transactionHash', (txid) => {
getElem('newTxid').innerHTML= 'txid: ' + getLink(txid) + '<span id="pending" style="color:red;"><img src="spin.gif">mining...</span>';
getElem('newComment').value = '';
})
.once('receipt', (receipt) => {
getElem('pending').innerHTML = '<br>(기록된 블록: ' + receipt.blockNumber + ')';
getElem('pending').style.cssText ='color:green;';
getElem('numComments').innerHTML = receipt.events.Commented.returnValues.count;
})
.on('error', (error) => {console.log(error)})
}
function removeAllChildNodes(parent) {
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
}
}
async function getComments() {
var numComments = await declaration.methods.numComments().call()
var startingBlock = await declaration.methods.blockByCounter(1).call();
getElem('numComments').innerHTML = numComments;
if (numComments > maxComments) {
startingBlock = await declaration.methods.blockByCounter(numComments-maxComments).call();
}
declaration.events.Commented({fromBlock: startingBlock})
.on('data', function(r){commentEventParser(r)})
.on('error', function(error, receipt){console.log(error);})
}
function commentEventParser(r){
if (commentHashes.includes(r.transactionHash)) {return}
commentHashes.push(r.transactionHash);
var newItem = document.createElement('li');
var txLink = document.createElement('span');
txLink.innerHTML = "tx: " + getLink(r.transactionHash);
newItem.appendChild(txLink);
var newPre = document.createElement('pre');
newPre.innerText = "작성자: " + r.returnValues.sender + '... on ' + convertTimestamp(r.returnValues.timestamp) + '\n\n' + r.returnValues.comment;
getElem('numComments').innerHTML = r.returnValues.count;
newItem.appendChild(newPre);
if (r.returnValues.sender == myAddr) {
var newMyItem = newItem.cloneNode(true);
if (myList.length == 0) {
myList.appendChild(newMyItem);
} else {
myList.insertBefore(newMyItem, myList.childNodes[0]);
}
}
if (allList.length == 0) {
allList.appendChild(newItem);
} else {
allList.insertBefore(newItem, allList.childNodes[0]);
}
}
async function getCommentsByAddr() {
var addr = getElem('targetAddr').value;
if (addr.length != 42) {
alert('0x 로 시작하는 이더리움 주소를 넣으세요.');
return;
}
var targetList = getElem('targetComments');
targetList.innerHTML = '';
var startingBlock = await declaration.methods.blockByCounter(1).call();
declaration.getPastEvents('Commented', {
filter:{sender: addr},
fromBlock: startingBlock,
toBlock: 'latest'
})
.then((result) => {
var i;
for (i = 0; i < result.length; i++) {
var newItem = document.createElement('li');
var newPre = document.createElement('pre');
var r = result[i];
newPre.innerText = "작성자: " + r.returnValues.sender + '... on ' + convertTimestamp(r.returnValues.timestamp) + '\n\n' + r.returnValues.comment;
newItem.appendChild(newPre);
if (targetList.length == 0) {
targetList.appendChild(newItem);
} else {
targetList.insertBefore(newItem, targetList.childNodes[0]);
}
}
})
}
/* helper function */
function getElem(elemId) {
return document.getElementById(elemId);
}
function getLink(addr) {
if (chainId == 1) {explorer = "https://etherscan.io";}
else if(chainId == 3) {explorer = "https://ropsten.etherscan.io";}
else if(chainId == 4) {explorer = "https://rinkeby.etherscan.io";}
else if(chainId == 5) {explorer = "https://goerli.etherscan.io";}
else if (chainId == 42) {explorer = "https://kovan.etherscan.io";}
else {
explorer = '';
console.log("unsupported chainid " + chainId);
}
if (addr.length == 42) {
return '<a target="_blank" style="text-decoration: underline;" href="' + explorer + '/address/' + addr + '">' + addr +'</a>';
} else {
return '<a target="_blank" style="text-decoration: underline;" href="' + explorer + '/tx/' + addr + '">' + addr +'</a>';
}
}
function convertTimestamp(unix_timestamp) {
return new Date(unix_timestamp*1000);
}
</script>
</body>
</html>