Added wallet example.
This commit is contained in:
parent
97154e49a6
commit
1bd95b127b
647
examples/wallet/index.html
Normal file
647
examples/wallet/index.html
Normal file
@ -0,0 +1,647 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Ethereum Wallet</title>
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
background-color: #eee;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 18px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centerer {
|
||||||
|
margin-left: 50%;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered:before {
|
||||||
|
box-shadow: -10px 0 15px -10px #999 inset;
|
||||||
|
content: " ";
|
||||||
|
height: 100%;
|
||||||
|
left: -10px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered:after {
|
||||||
|
box-shadow: 10px 0 15px -10px #999 inset;
|
||||||
|
content: " ";
|
||||||
|
height: 100%;
|
||||||
|
right: -10px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered {
|
||||||
|
background-color: #fff;
|
||||||
|
border-left: 1px solid #888;
|
||||||
|
border-right: 1px solid #888;
|
||||||
|
dbox-shadow: -1px 0 15px 0 #999;
|
||||||
|
margin-left: -370px;
|
||||||
|
min-height: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
position: relative;
|
||||||
|
width: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
text-align: justify;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
text-align: left;
|
||||||
|
padding: 0 15px 15px 0;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
padding: 0 15px 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text] {
|
||||||
|
border: 1px solid #555;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 10px;
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=password] {
|
||||||
|
border: 1px solid #555;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 10px;
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=file] {
|
||||||
|
dbackground: #fff;
|
||||||
|
border: 1px solid #555;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
opacity: 0;
|
||||||
|
padding: 10px;
|
||||||
|
position: relative;
|
||||||
|
dvisibility: hidden;
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text].readonly {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file {
|
||||||
|
dddbackground: #fff;
|
||||||
|
border: 1px solid green;
|
||||||
|
color: #444;
|
||||||
|
dcursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
margin-top: 2px;
|
||||||
|
padding: 13px 10px 12px;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
width: 478px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option {
|
||||||
|
border: 1px solid #999;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
opacity: 0.3;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
transition: opacity 0.1s linear;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option.selected {
|
||||||
|
dbox-shadow: 0px 0px 5px #888;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option:hover {
|
||||||
|
box-shadow: 0px 0px 5px #888;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.activity {
|
||||||
|
font-family: monospace;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.activity a {
|
||||||
|
display: block;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
color: #888;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit {
|
||||||
|
border: 1px solid #555;
|
||||||
|
box-shadow: 0px 0px 5px #888;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
transition: opacity 0.1s linear;
|
||||||
|
width: 480px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit:hover {
|
||||||
|
border: 1px solid #999;
|
||||||
|
box-shadow: 0px 0px 5px #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit:active {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit.disable {
|
||||||
|
box-shadow: none;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit.disable:hover {
|
||||||
|
border: 1px solid #555;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit.disable:active {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="centerer" id="screen-select">
|
||||||
|
<div class="centered">
|
||||||
|
<h1>Ethereum Wallet Tool</h1>
|
||||||
|
<hr />
|
||||||
|
<h2>Summon Brain Wallet</h2>
|
||||||
|
<p>
|
||||||
|
A brain wallet generates an <i>Ethereum</i> wallet from a username and a password
|
||||||
|
without using any servers to store your information. If you lose your username
|
||||||
|
or password, <b>no one</b> can help you recover them. Anyone who can guess your
|
||||||
|
username and password can steal your funds. Brain wallets should <b>not</b> be
|
||||||
|
considered a safe way to store large amounts of ether nor for long periods of time.
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>E-mail Address:</th>
|
||||||
|
<td><input type="text" placeholder="(e-mail address)" id="select-brainwallet-username" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Password:</th>
|
||||||
|
<td><input type="password" placeholder="(password)" id="select-brainwallet-password" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Confirm Password:</th>
|
||||||
|
<td><input type="password" placeholder="(same password)" id="select-brainwallet-confirm-password" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
<td>
|
||||||
|
<div id="select-submit-brainwallet" class="submit disable">Summon Brain Wallet</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<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 />
|
||||||
|
<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="option left selected" id="option-morden">Morden (testnet)</div>
|
||||||
|
<div class="option right" id="option-homestead">Homestead (mainnet)</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-wallet.js"></script>
|
||||||
|
|
||||||
|
<!-- This greatly improves the scrypt PBKDF performance -->
|
||||||
|
<script type="text/javascript" src="./setImmediate.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var inputUsername = document.getElementById('select-brainwallet-username');
|
||||||
|
var inputPassword = document.getElementById('select-brainwallet-password');
|
||||||
|
var inputConfirmPassword = document.getElementById('select-brainwallet-confirm-password');
|
||||||
|
var submit = document.getElementById('select-submit-brainwallet');
|
||||||
|
|
||||||
|
function checkBrainwallet() {
|
||||||
|
if (inputUsername.value && inputPassword.value && inputPassword.value === inputConfirmPassword.value) {
|
||||||
|
submit.classList.remove('disable');
|
||||||
|
} else {
|
||||||
|
submit.classList.add('disable');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inputUsername.oninput = checkBrainwallet;
|
||||||
|
inputPassword.oninput = checkBrainwallet;
|
||||||
|
inputConfirmPassword.oninput = checkBrainwallet;
|
||||||
|
|
||||||
|
setEnter(inputUsername, submit);
|
||||||
|
setEnter(inputPassword, submit);
|
||||||
|
setEnter(inputConfirmPassword, submit);
|
||||||
|
|
||||||
|
submit.onclick = function() {
|
||||||
|
if (submit.classList.contains('disable')) { return; }
|
||||||
|
|
||||||
|
var username = new Wallet.utils.Buffer(inputUsername.value, 'utf8');
|
||||||
|
var password = new Wallet.utils.Buffer(inputPassword.value, 'utf8');
|
||||||
|
|
||||||
|
showLoading('Summoning Brain Wallet...');
|
||||||
|
|
||||||
|
cancelScrypt = false;
|
||||||
|
|
||||||
|
Wallet.summonBrainWallet(username, password, function(error, wallet, progress) {
|
||||||
|
if (error) {
|
||||||
|
if (error.message !== 'cancelled') {
|
||||||
|
alert('Unknown error');
|
||||||
|
}
|
||||||
|
showSelect();
|
||||||
|
|
||||||
|
} else if (wallet) {
|
||||||
|
showWallet(wallet);
|
||||||
|
document.getElementById('wallet-username').textContent = inputUsername.value;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
updateLoading(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cancelScrypt;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(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);
|
||||||
|
|
||||||
|
targetDrop.addEventListener('dragover', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
targetDrop.classList.add('highlight');
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
targetDrop.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 (Wallet.isCrowdsaleWallet(json)) {
|
||||||
|
showWallet(Wallet.decryptCrowdsale(json, password));
|
||||||
|
|
||||||
|
} else if (Wallet.isValidWallet(json)) {
|
||||||
|
showLoading('Decrypting Wallet...');
|
||||||
|
var password = new Wallet.utils.Buffer(inputPassword.value);
|
||||||
|
|
||||||
|
cancelScrypt = false;
|
||||||
|
|
||||||
|
Wallet.decrypt(json, password, function(error, wallet, progress) {
|
||||||
|
if (error) {
|
||||||
|
if (error.message === 'invalid password') {
|
||||||
|
alert('Wrong Password');
|
||||||
|
} else {
|
||||||
|
console.log(error);
|
||||||
|
alert('Error Decrypting Wallet');
|
||||||
|
}
|
||||||
|
showSelect();
|
||||||
|
|
||||||
|
} else if (wallet) {
|
||||||
|
showWallet(wallet);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
updateLoading(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cancelScrypt;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
alert('Unknown JSON wallet format');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fileReader.readAsText(inputFile.files[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
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 = Wallet.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); }
|
||||||
|
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 {
|
||||||
|
Wallet.getAddress(inputTargetAddress.value);
|
||||||
|
Wallet.parseEther(inputAmount.value);
|
||||||
|
} catch (error) {
|
||||||
|
submit.classList.add('disable');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
submit.classList.remove('disable');
|
||||||
|
}
|
||||||
|
inputTargetAddress.oninput = check;
|
||||||
|
inputAmount.oninput = check;
|
||||||
|
|
||||||
|
var optionMorden = document.getElementById('option-morden');
|
||||||
|
var optionHomestead = document.getElementById('option-homestead');
|
||||||
|
|
||||||
|
// Select the morden network
|
||||||
|
optionMorden.onclick = function() {
|
||||||
|
if (optionMorden.classList.contains('selected')) { return; }
|
||||||
|
addActivity('! Switched network: Morden');
|
||||||
|
activeWallet.provider = new Wallet.providers.EtherscanProvider({testnet: true});
|
||||||
|
optionMorden.classList.add('selected');
|
||||||
|
optionHomestead.classList.remove('selected');
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the homestead network
|
||||||
|
optionHomestead.onclick = function() {
|
||||||
|
if (optionHomestead.classList.contains('selected')) { return; }
|
||||||
|
addActivity('! Switched network: Homestead');
|
||||||
|
activeWallet.provider = new Wallet.providers.EtherscanProvider({testnet: false});
|
||||||
|
optionMorden.classList.remove('selected');
|
||||||
|
optionHomestead.classList.add('selected');
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send ether
|
||||||
|
submit.onclick = function() {
|
||||||
|
var gasPrice = (activeWallet.provider.testnet ? 0x4a817c800: 0xba43b7400);
|
||||||
|
console.log('GasPrice: ' + gasPrice);
|
||||||
|
|
||||||
|
var targetAddress = Wallet.getAddress(inputTargetAddress.value);
|
||||||
|
var amountWei = Wallet.parseEther(inputAmount.value);
|
||||||
|
activeWallet.send(targetAddress, amountWei, {
|
||||||
|
gasPrice: gasPrice,
|
||||||
|
gasLimit: 21000,
|
||||||
|
}).then(function(txid) {
|
||||||
|
var url = (activeWallet.provider.testnet ? 'https://testnet.etherscan.io/tx/': 'https://etherscan.io/tx/') + txid;
|
||||||
|
addActivity('< Transaction sent: ' + txid.substring(0, 20) + '...', url);
|
||||||
|
alert('Success!');
|
||||||
|
|
||||||
|
inputTargetAddress.value = '';
|
||||||
|
inputAmount.value = '';
|
||||||
|
submit.classList.add('disable');
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}, function(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
var loadingStatus = document.getElementById('loading-status');
|
||||||
|
function updateLoading(progress) {
|
||||||
|
loadingStatus.value = (parseInt(progress * 100)) + '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showWallet(wallet) {
|
||||||
|
activeWallet = wallet;
|
||||||
|
activeWallet.provider = new Wallet.providers.EtherscanProvider({testnet: true});
|
||||||
|
|
||||||
|
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 Wallet(privateKey));
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
175
examples/wallet/setImmediate.js
Normal file
175
examples/wallet/setImmediate.js
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
(function (global, undefined) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
if (global.setImmediate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextHandle = 1; // Spec says greater than zero
|
||||||
|
var tasksByHandle = {};
|
||||||
|
var currentlyRunningATask = false;
|
||||||
|
var doc = global.document;
|
||||||
|
var setImmediate;
|
||||||
|
|
||||||
|
function addFromSetImmediateArguments(args) {
|
||||||
|
tasksByHandle[nextHandle] = partiallyApplied.apply(undefined, args);
|
||||||
|
return nextHandle++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function accepts the same arguments as setImmediate, but
|
||||||
|
// returns a function that requires no arguments.
|
||||||
|
function partiallyApplied(handler) {
|
||||||
|
var args = [].slice.call(arguments, 1);
|
||||||
|
return function() {
|
||||||
|
if (typeof handler === "function") {
|
||||||
|
handler.apply(undefined, args);
|
||||||
|
} else {
|
||||||
|
(new Function("" + handler))();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function runIfPresent(handle) {
|
||||||
|
// From the spec: "Wait until any invocations of this algorithm started before this one have completed."
|
||||||
|
// So if we're currently running a task, we'll need to delay this invocation.
|
||||||
|
if (currentlyRunningATask) {
|
||||||
|
// Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a
|
||||||
|
// "too much recursion" error.
|
||||||
|
setTimeout(partiallyApplied(runIfPresent, handle), 0);
|
||||||
|
} else {
|
||||||
|
var task = tasksByHandle[handle];
|
||||||
|
if (task) {
|
||||||
|
currentlyRunningATask = true;
|
||||||
|
try {
|
||||||
|
task();
|
||||||
|
} finally {
|
||||||
|
clearImmediate(handle);
|
||||||
|
currentlyRunningATask = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearImmediate(handle) {
|
||||||
|
delete tasksByHandle[handle];
|
||||||
|
}
|
||||||
|
|
||||||
|
function installNextTickImplementation() {
|
||||||
|
setImmediate = function() {
|
||||||
|
var handle = addFromSetImmediateArguments(arguments);
|
||||||
|
process.nextTick(partiallyApplied(runIfPresent, handle));
|
||||||
|
return handle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function canUsePostMessage() {
|
||||||
|
// The test against `importScripts` prevents this implementation from being installed inside a web worker,
|
||||||
|
// where `global.postMessage` means something completely different and can't be used for this purpose.
|
||||||
|
if (global.postMessage && !global.importScripts) {
|
||||||
|
var postMessageIsAsynchronous = true;
|
||||||
|
var oldOnMessage = global.onmessage;
|
||||||
|
global.onmessage = function() {
|
||||||
|
postMessageIsAsynchronous = false;
|
||||||
|
};
|
||||||
|
global.postMessage("", "*");
|
||||||
|
global.onmessage = oldOnMessage;
|
||||||
|
return postMessageIsAsynchronous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function installPostMessageImplementation() {
|
||||||
|
// Installs an event handler on `global` for the `message` event: see
|
||||||
|
// * https://developer.mozilla.org/en/DOM/window.postMessage
|
||||||
|
// * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
|
||||||
|
|
||||||
|
var messagePrefix = "setImmediate$" + Math.random() + "$";
|
||||||
|
var onGlobalMessage = function(event) {
|
||||||
|
if (event.source === global &&
|
||||||
|
typeof event.data === "string" &&
|
||||||
|
event.data.indexOf(messagePrefix) === 0) {
|
||||||
|
runIfPresent(+event.data.slice(messagePrefix.length));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (global.addEventListener) {
|
||||||
|
global.addEventListener("message", onGlobalMessage, false);
|
||||||
|
} else {
|
||||||
|
global.attachEvent("onmessage", onGlobalMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
setImmediate = function() {
|
||||||
|
var handle = addFromSetImmediateArguments(arguments);
|
||||||
|
global.postMessage(messagePrefix + handle, "*");
|
||||||
|
return handle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function installMessageChannelImplementation() {
|
||||||
|
var channel = new MessageChannel();
|
||||||
|
channel.port1.onmessage = function(event) {
|
||||||
|
var handle = event.data;
|
||||||
|
runIfPresent(handle);
|
||||||
|
};
|
||||||
|
|
||||||
|
setImmediate = function() {
|
||||||
|
var handle = addFromSetImmediateArguments(arguments);
|
||||||
|
channel.port2.postMessage(handle);
|
||||||
|
return handle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function installReadyStateChangeImplementation() {
|
||||||
|
var html = doc.documentElement;
|
||||||
|
setImmediate = function() {
|
||||||
|
var handle = addFromSetImmediateArguments(arguments);
|
||||||
|
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
|
||||||
|
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
|
||||||
|
var script = doc.createElement("script");
|
||||||
|
script.onreadystatechange = function () {
|
||||||
|
runIfPresent(handle);
|
||||||
|
script.onreadystatechange = null;
|
||||||
|
html.removeChild(script);
|
||||||
|
script = null;
|
||||||
|
};
|
||||||
|
html.appendChild(script);
|
||||||
|
return handle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function installSetTimeoutImplementation() {
|
||||||
|
setImmediate = function() {
|
||||||
|
var handle = addFromSetImmediateArguments(arguments);
|
||||||
|
setTimeout(partiallyApplied(runIfPresent, handle), 0);
|
||||||
|
return handle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.
|
||||||
|
var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);
|
||||||
|
attachTo = attachTo && attachTo.setTimeout ? attachTo : global;
|
||||||
|
|
||||||
|
// Don't get fooled by e.g. browserify environments.
|
||||||
|
if ({}.toString.call(global.process) === "[object process]") {
|
||||||
|
// For Node.js before 0.9
|
||||||
|
installNextTickImplementation();
|
||||||
|
|
||||||
|
} else if (canUsePostMessage()) {
|
||||||
|
// For non-IE10 modern browsers
|
||||||
|
installPostMessageImplementation();
|
||||||
|
|
||||||
|
} else if (global.MessageChannel) {
|
||||||
|
// For web workers, where supported
|
||||||
|
installMessageChannelImplementation();
|
||||||
|
|
||||||
|
} else if (doc && "onreadystatechange" in doc.createElement("script")) {
|
||||||
|
// For IE 6–8
|
||||||
|
installReadyStateChangeImplementation();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// For older browsers
|
||||||
|
installSetTimeoutImplementation();
|
||||||
|
}
|
||||||
|
|
||||||
|
attachTo.setImmediate = setImmediate;
|
||||||
|
attachTo.clearImmediate = clearImmediate;
|
||||||
|
}(typeof self === "undefined" ? typeof global === "undefined" ? this : global : self));
|
Loading…
Reference in New Issue
Block a user