UNPKG

ethers

Version:
475 lines (418 loc) 20.1 kB
<html> <head> <title>Ethereum Wallet</title> <link rel="stylesheet" type="text/css" href="./style.css"> </head> <body> <div class="centerer" id="screen-select"> <div class="centered"> <h1>Ethereum Wallet Tool</h1> <hr /> <h2>Load JSON Wallet</h2> <p> If you have a JSON wallet file from <i>geth</i> or from the initial <i>Ethereum</i> crowd sale, you can decrypt it here. No information is shared with <b>any</b> server. </p> <table> <tr> <th>JSON Wallet:</th> <td><div class="file" id="select-wallet-drop">Drop JSON wallet file here</div><input type="file" id="select-wallet-file" /></td> </tr> <tr> <th>Password:</th> <td><input type="password" placeholder="(password)" id="select-wallet-password" /></td> </tr> <tr> <td> </td> <td> <div id="select-submit-wallet" class="submit disable">Unlock JSON Wallet</div> </td> </tr> </table> <hr /> <h2>Mnemonic Phrase Wallet</h2> <p> If you have a 12 word mnemonic phrase, you can generate your wallet here. No information is shared with <b>any</b> server. </p> <table> <tr> <th>Mnemonic Phrase:</th> <td><input type="text" placeholder="(mnemonic phrase)" id="select-mnemonic-phrase" /></td> </tr> <tr> <th>Path:</th> <td><input type="text" placeholder="(path)" id="select-mnemonic-path" value="m/44'/60'/0'/0/0" /></td> </tr> <tr> <td> </td> <td> <div id="select-submit-mnemonic" class="submit disable">Derive Wallet</div> </td> </tr> </table> <hr /> <h2>Raw Private Key</h2> <p> </p> <table> <tr> <th>Private Key:</th> <td><input type="text" placeholder="(private key)" id="select-privatekey" /></td> </tr> <tr> <td> </td> <td> <div id="select-submit-privatekey" class="submit disable">Load Raw Private Key</div> </td> </tr> </table> <hr /> <h3>Disclaimer:</h3> <p> This is beta software, with no warranty. <b>Use at your own risk.</b> </p> </div> </div> <div class="centerer hidden" id="screen-loading"> <div class="centered"> <h1>Loading Wallet</h1> <hr /> <h2 id="loading-header"></h2> <table> <tr> <th>Progress:</th> <td> <input type="text" readonly="readonly" class="readonly" id="loading-status" value="" /></div> </td> </tr> <tr> <td> </td> <td> <div id="loading-cancel" class="submit">Cancel</div> </td> </tr> </table> <hr /> <h3>Disclaimer:</h3> <p> This is beta software, with no warranty. <b>Use at your own risk.</b> </p> </div> </div> <div class="centerer hidden" id="screen-wallet"> <div class="centered"> <h1>Ethereum Wallet<span id="wallet-username" class="username right"></span></h1> <hr /> <h3>Wallet Details:</h3> <table> <tr> <th>Address:</th> <td> <input type="text" readonly="readonly" class="readonly" id="wallet-address" value="" /></div> </td> </tr> <tr> <th>Network:</th> <td> <div class="clearfix"></div> <div class="network option" data-network="ropsten">Ropsten<br /><span>testnet</span></div> <div class="network option" data-network="rinkeby">Rinkeby<br /><span>testnet</span></div> <div class="network option" data-network="kovan">Kovan<br /><span>testnet</span></div> <div class="network option last selected" data-network="homestead">Homestead<br /><span>mainnet</span></div> <div class="clearfix"></div> </td> </tr> <tr> <th>Balance:</th> <td> <input type="text" readonly="readonly" class="readonly" id="wallet-balance" value="0.0" /></div> </td> </tr> <tr> <th>Nonce:</th> <td> <input type="text" readonly="readonly" class="readonly" id="wallet-transaction-count" value="0" /></div> </td> </tr> <tr> <td> </td> <td> <div id="wallet-submit-refresh" class="submit">Refresh</div> </td> </tr> </table> <h3>Send Ether:</h3> <table> <tr> <th>Target Address:</th> <td><input type="text" placeholder="(target address)" id="wallet-send-target-address" /></td> </tr> <tr> <th>Amount:</th> <td><input type="text" placeholder="(amount)" id="wallet-send-amount" /></td> </tr> <tr> <td> </td> <td> <div id="wallet-submit-send" class="submit disable">Send Ether</div> </td> </tr> </table> <h3>Session Activity</h3> <div id="wallet-activity" class="activity"></div> <hr /> <h3>Disclaimer:</h3> <p> This is beta software, with no warranty. <b>Use at your own risk.</b> </p> </div> </div> <script type="text/javascript" src="../../dist/ethers.js"></script> <script type="text/javascript"> function query(el, selector) { if (!selector) { selector = el; el = document; } return Array.prototype.slice.call(el.querySelectorAll(selector)); } function setEnter(source, target) { source.onkeyup = function(e) { if (e.which === 13) { target.click(); } } } var cancelScrypt = false; document.getElementById('loading-cancel').onclick = function() { cancelScrypt = true; }; var updateLoading = (function() { var loadingStatus = document.getElementById('loading-status'); return (function(progress) { loadingStatus.value = (parseInt(progress * 100)) + '%'; return cancelScrypt; }); })(); // JSON Wallet (function() { var inputFile = document.getElementById('select-wallet-file'); var targetDrop = document.getElementById('select-wallet-drop'); var inputPassword = document.getElementById('select-wallet-password'); var submit = document.getElementById('select-submit-wallet'); function check() { if (inputFile.files && inputFile.files.length === 1) { submit.classList.remove('disable'); targetDrop.textContent = inputFile.files[0].name; } else { submit.classList.add('disable'); } } inputFile.onchange = check; inputPassword.oninput = check; setEnter(inputPassword, submit); inputFile.addEventListener('dragover', function(event) { event.preventDefault(); event.stopPropagation(); targetDrop.classList.add('highlight'); }, true); inputFile.addEventListener('drop', function(event) { targetDrop.classList.remove('highlight'); }, true); submit.onclick = function() { if (submit.classList.contains('disable')) { return; } var fileReader = new FileReader(); fileReader.onload = function(e) { var json = e.target.result; if (ethers.utils.getJsonWalletAddress(json)) { showLoading('Decrypting Wallet...'); cancelScrypt = false; ethers.Wallet.fromEncryptedJson(json, inputPassword.value, updateLoading).then(function(wallet) { showWallet(wallet); }, function(error) { if (error.message === 'invalid password') { alert('Wrong Password'); } else { console.log(error); alert('Error Decrypting Wallet'); } showSelect(); }); } else { alert('Unknown JSON wallet format'); } }; fileReader.readAsText(inputFile.files[0]); }; })(); // Raw Private Key (function() { var inputPrivatekey = document.getElementById('select-privatekey'); var submit = document.getElementById('select-submit-privatekey'); function check() { if (inputPrivatekey.value.match(/^(0x)?[0-9A-fa-f]{64}$/)) { submit.classList.remove('disable'); } else { submit.classList.add('disable'); } } inputPrivatekey.oninput = check; setEnter(inputPrivatekey, submit); submit.onclick = function() { if (submit.classList.contains('disable')) { return; } var privateKey = inputPrivatekey.value; if (privateKey.substring(0, 2) !== '0x') { privateKey = '0x' + privateKey; } showWallet(new ethers.Wallet(privateKey)); } })(); // Mnemonic Phrase (function() { var inputPhrase = document.getElementById('select-mnemonic-phrase'); var inputPath = document.getElementById('select-mnemonic-path'); var submit = document.getElementById('select-submit-mnemonic'); function check() { if (ethers.HDNode.isValidMnemonic(inputPhrase.value)) { submit.classList.remove('disable'); } else { submit.classList.add('disable'); } } inputPhrase.oninput = check; inputPath.oninput = check; setEnter(inputPhrase, submit); setEnter(inputPath, submit); submit.onclick = function() { if (submit.classList.contains('disable')) { return; } showWallet(ethers.Wallet.fromMnemonic(inputPhrase.value, inputPath.value)); } })(); var activeWallet = null; function showError(error) { alert('Error \u2014 ' + error.message); } // Refresh balance and transaction count in the UI var refresh = (function() { var inputBalance = document.getElementById('wallet-balance'); var inputTransactionCount = document.getElementById('wallet-transaction-count'); var submit = document.getElementById('wallet-submit-refresh'); function refresh() { addActivity('> Refreshing details...'); activeWallet.getBalance('pending').then(function(balance) { addActivity('< Balance: ' + balance.toString(10)); inputBalance.value = ethers.utils.formatEther(balance, { commify: true }); }, function(error) { showError(error); }); activeWallet.getTransactionCount('pending').then(function(transactionCount) { addActivity('< TransactionCount: ' + transactionCount); inputTransactionCount.value = transactionCount; }, function(error) { showError(error); }); } submit.onclick = refresh; return refresh; })(); var addActivity = (function() { var activity = document.getElementById('wallet-activity'); return function(message, url) { var line = document.createElement('a'); line.textContent = message; if (url) { line.setAttribute('href', url); line.setAttribute('target', '_blank'); } activity.appendChild(line); } })(); // Set up the wallet page (function() { var inputTargetAddress = document.getElementById('wallet-send-target-address'); var inputAmount = document.getElementById('wallet-send-amount'); var submit = document.getElementById('wallet-submit-send'); // Validate the address and value (to enable the send button) function check() { try { ethers.utils.getAddress(inputTargetAddress.value); ethers.utils.parseEther(inputAmount.value); } catch (error) { submit.classList.add('disable'); return; } submit.classList.remove('disable'); } inputTargetAddress.oninput = check; inputAmount.oninput = check; query('.network.option').forEach(function(el) { var network = el.getAttribute('data-network'); el.onclick = function() { addActivity('! Switched network: ' + network); activeWallet = activeWallet.connect(ethers.providers.getDefaultProvider(network)); query('.network.option.selected').forEach(function(el) { el.classList.remove('selected'); }); el.classList.add('selected'); refresh(); }; }); // Send ether submit.onclick = function() { // Matt (from Etherscan) is working on a gasPrice API call, which // should be done within a week or so. // @TODO //var gasPrice = (activeWallet.provider.testnet ? 0x4a817c800: 0xba43b7400); //console.log('GasPrice: ' + gasPrice); var targetAddress = ethers.utils.getAddress(inputTargetAddress.value); var amountWei = ethers.utils.parseEther(inputAmount.value); activeWallet.sendTransaction({ to: targetAddress, value: amountWei, //gasPrice: activeWallet.provider.getGasPrice(), //gasLimit: 21000, }).then(function(tx) { console.log(tx); // Since we only use standard networks, network will always be known var tag = activeWallet.provider.network.name + '.'; if (tag === 'homestead.') { tag = ''; } var url = 'https://' + tag + 'etherscan.io/tx/' + tx.hash; addActivity('< Transaction sent: ' + tx.hash.substring(0, 20) + '...', url); alert('Success!'); inputTargetAddress.value = ''; inputAmount.value = ''; submit.classList.add('disable'); refresh(); }, function(error) { console.log(error); showError(error); }); } })(); function showSelect() { document.getElementById('screen-select').style.display = 'block'; document.getElementById('screen-loading').style.display = 'none'; document.getElementById('screen-wallet').style.display = 'none'; } function showLoading(title) { document.getElementById('screen-select').style.display = 'none'; document.getElementById('screen-loading').style.display = 'block'; document.getElementById('screen-wallet').style.display = 'none'; document.getElementById('loading-header').textContent = title; } function showWallet(wallet) { var network = document.querySelector('.network.option.selected').getAttribute('data-network'); activeWallet = wallet.connect(new ethers.providers.getDefaultProvider(network)); document.getElementById('screen-select').style.display = 'none'; document.getElementById('screen-loading').style.display = 'none'; document.getElementById('screen-wallet').style.display = 'block'; var inputWalletAddress = document.getElementById('wallet-address'); inputWalletAddress.value = wallet.address; inputWalletAddress.onclick = function() { this.select(); }; refresh(); } //var privateKey = '0x3141592653589793238462643383279502884197169399375105820974944592'; //showWallet(new ethers.Wallet(privateKey)); </script> </body> </html>