diff options
Diffstat (limited to 'static/js/wallet.coffee')
| -rw-r--r-- | static/js/wallet.coffee | 456 |
1 files changed, 0 insertions, 456 deletions
diff --git a/static/js/wallet.coffee b/static/js/wallet.coffee deleted file mode 100644 index 1beefd23..00000000 --- a/static/js/wallet.coffee +++ /dev/null @@ -1,456 +0,0 @@ -g = exports ? this -g.proceed = false -g.api = '/blockcypher/v1/btc/main' - -validators = - address: (e) -> - return true if e.val() is '' - try - bitcoin.address.fromBase58Check(e.val()) - catch - return false - - key: (e) -> - $('#keytype').val() != 'unknown' - -errors = - address: 'Invalid address.' - key: 'Could not detect key type.' - -$(-> - getUser() - - $('#types').attr('data-content', """ - Bitcoin Address (starts with 1 or 3)<br /> - Private Key (starts with 5 or L)<br /> - HD Wallet pubkey (starts with xpub)<br /> - HD Wallet private key (starts with xprv)<br /> - AES Encrypted Private Key (starts with U)<br /> - BIP38 Encrypted Private Key (starts with 6)<br /> - BIP39 Mnemonic (series of 12-24 english words) - """) - .popover(html: true) - .on("show.bs.popover", -> $(this).data("bs.popover").tip().css(minWidth: "400px")) - - $('form').validator(custom: validators, errors: errors, delay: 1200) - $('[data-toggle=tooltip]').tooltip(trigger: 'hover') - - $('#key').keyup(-> - val = $(this).val() - - $('#keytype').val('unknown') - - switch val[0] - when '1' - try - bitcoin.address.fromBase58Check(val) - $('#keytype').val('address') - when 'm' - try - bitcoin.address.fromBase58Check(val) - $('#keytype').val('address') - when '5', \ - 'L', \ - 'K' - try - bitcoin.ECPair.fromWIF(val) - $('#keytype').val('wif') - when 'U' - try - if CryptoJS.AES.decrypt(val, g.password).toString(CryptoJS.enc.Utf8) - $('#keytype').val('aes') - when '6' - if bip38().verify(val) - $('#keytype').val('bip38') - when 'x' - if $(this).val()[3] is 'b' - try - bitcoin.HDNode.fromBase58(val) - $('#keytype').val('xpub') - else - try - bitcoin.HDNode.fromBase58(val) - $('#keytype').val('xprv') - else - if val.split(' ').length in [12, 15, 18, 21, 24] and bip39.validateMnemonic(val) - $('#keytype').val('bip39') - ) - - $('#save').click(-> - $('.form-control').blur() - if $('#keys .has-error').length > 0 - $('#keys .has-error').effect('shake', 500) - return - - key = $('#key').val() - proceed = true - - switch $('#keytype').val() - when 'address' - $('#pubkey').val(key) - $('#privkey').val('') - when 'wif' - pubkey = bitcoin.ECPair.fromWIF(key).getAddress() - privkey = CryptoJS.AES.encrypt(key, g.password) - $('#pubkey').val(pubkey) - $('#privkey').val(privkey) - when 'aes' - try - pubkey = bitcoin.HDNode.fromBase58(CryptoJS.AES.decrypt(key, g.password).toString(CryptoJS.enc.Utf8)).neutered().toString() - $('#pubkey').val(pubkey) - $('#privkey').val(key) - catch - try - pubkey = bitcoin.ECPair.fromWIF(CryptoJS.AES.decrypt(key, g.password).toString(CryptoJS.enc.Utf8)).getAddress() - $('#pubkey').val(pubkey) - $('#privkey').val(key) - catch - proceed = false - when 'bip38' - wif = bip38().decrypt(key, g.password) - pubkey = bitcoin.ECPair.fromWIF(wif).getAddress() - privkey = CryptoJS.AES.encrypt(wif, g.password) - $('#pubkey').val(pubkey) - $('#privkey, #key').val(privkey) - when 'xpub' - $('#pubkey').val(key) - $('#privkey').val('') - when 'xprv' - pubkey = bitcoin.HDNode.fromBase58(key).neutered().toString() - privkey = CryptoJS.AES.encrypt(key, g.password) - $('#pubkey').val(pubkey) - $('#privkey').val(privkey) - when 'bip39' - master = bitcoin.HDNode.fromSeedBuffer(bip39.mnemonicToSeed(key)).deriveHardened(44).deriveHardened(0) - pubkey = master.neutered().toString() - privkey = CryptoJS.AES.encrypt(master.toString(), g.password) - $('#pubkey').val(pubkey) - $('#privkey').val(privkey) - - if proceed - updateUser() - $('#keys').hide() - $('#keys_updated').fadeIn() - $('#balances').hide() - $('#fetching').show() - ) - - - $('#withdrawal form input[type=button]').click(sendTransaction) - - $('#currency_toggle').click(-> - if $(this).html() is g.user.unit - $(this).html(g.user.currency) - g.amount = parseFloat($('#amount').val()).toFixed(precision()) - amount = (g.amount * g.exchange / multiplier()).toFixed(2) - $('#amount').val(amount) - $('#amount').attr('step', 0.01) - $('#amount').attr('max', (g.balance * g.exchange / multiplier()).toFixed(2)) - else - $(this).html(g.user.unit) - $('#amount').val(convertedAmount()) - $('#amount').attr('step', 0.00000001 * multiplier()) - $('#amount').attr('max', g.balance) - ) - - $('#max').click(-> - if $('#currency_toggle').html() is g.user.unit - $('#amount').val(g.balance).blur() - else - g.amount = parseFloat(g.balance).toFixed(precision()) - amount = (g.balance / multiplier() * g.exchange).toFixed(2) - $('#amount').val(amount).blur() - ) - - $('#amount').change(-> - if $('#currency_toggle').html() is g.user.unit - $(this).val(parseFloat($(this).val()).toFixed(precision())) - else - $(this).val(parseFloat($(this).val()).toFixed(2)) - - if parseFloat($(this).val()) > parseFloat($(this).attr('max')) - $(this).val($(this).attr('max')) - ) - - $('#password').keyup(-> - try - if g.user.privkey - g.privkey = CryptoJS.AES.decrypt(g.user.privkey, $(this).val()).toString(CryptoJS.enc.Utf8) - - if g.privkey[0] is 'x' - g.key = bitcoin.HDNode.fromBase58(g.privkey) - else - g.key = bitcoin.ECPair.fromWIF(g.privkey) - - $('#key').val(g.privkey).keyup() - else - $('#key').val(g.user.pubkey).keyup() - - $(this).closest('.form-group').hide() - $('.wallet').fadeIn() - g.password = $(this).val() - ) - - $('#manage').click(-> - $('#withdrawal').hide() - $('#keys').show() - $('#privkey').val(g.user.privkey) - ) - - $('#withdraw').click(-> - $('#withdrawal').show() - $('#amount').focus() - $('#keys').hide() - $('#withdrawal form').validator('destroy') - $('#withdrawal form').validator(custom: validators, errors: errors, delay: 1200) - ) - - $('#cancel').click(-> - $('#keys').hide() - if g.balance > 0 and g.user.privkey - $('#withdrawal form').validator('destroy') - $('#withdrawal form').validator(custom: validators, errors: errors, delay: 1200) - $('#withdrawal').show() - $('#amount').focus() - ) - - $('#backup').click(-> - url = 'data:application/json;base64,' + btoa(JSON.stringify(g.user.privkey)) - a = document.createElement('a') - a.setAttribute('href', url) - a.setAttribute('download', 'wallet.json.aes') - a.click() - ) - - $('#generate').click(-> - bootbox.confirm('<h3>Are you sure?</h3> <p>This will overwrite your existing wallet so make sure that you have the backup we sent to your email in case you want to restore it.</p>', (result) -> - if result - mnemonic = bip39.generateMnemonic() - key = bitcoin.HDNode.fromSeedBuffer(bip39.mnemonicToSeed(mnemonic)).deriveHardened(44).deriveHardened(0) - $('#key').val(key.toString()).effect('highlight', {}, 2000).keyup() - ) - ) - - $('.close').on('click', -> $(this).closest('.alert').fadeOut()) -) - -getUser = -> - $.getJSON("/#{$('#username').val()}.json", (user) -> - g.user = user - $('#key').val(user.pubkey) - $('#pubkey').val(user.pubkey) - $('#privkey').val(user.privkey) - $('#address').val(user.address) - $('.address').html(user.address) - $('#unit').html(user.unit) - $('#currency_toggle').html(user.unit) - $('#amount').attr('step', 0.00000001 * multiplier()) - $('#password').closest('.form-group').show() - $('#password').focus() - - getExchangeRate() - $('#password').keyup() - ) - -getExchangeRate = -> - $.get("/ticker?currency=#{g.user.currency}&symbol=#{g.user.symbol}&type=bid", (exchange) -> - g.exchange = exchange - createWallet() - ) - -createWallet = -> - $.get("#{g.api}/wallets", (data) -> - if g.user.username in data.wallet_names - getBalance() - else - params = name: g.user.username - - if isBip32(g.user.pubkey) - params.extended_public_key = g.user.pubkey - params.subchain_indexes = [0,1] - - $.post("#{g.api}/wallets/hd", JSON.stringify(params)).done(getBalance).fail(-> $('.wallet').fadeIn()) - else - params.addresses = [g.user.pubkey] - $.post("#{g.api}/wallets", JSON.stringify(params)).done(getBalance).fail(-> $('.wallet').fadeIn()) - ) - - -getBalance = -> - $.get("#{g.api}/addrs/#{g.user.username}/balance?omitWalletAddresses=true", (data) -> - balance = data.final_balance - g.balance = parseFloat(balance.toBTC()) - fiat = balance.toFiat() - $('#balance').html(g.balance) - $('#fiat').html("#{fiat} #{g.user.currency}") - $('#amount').attr('max', g.balance) - $('#balances').show() - $('#fetching').hide() - - if g.balance > 0 and g.user.privkey - $('#keys').hide() - $('#withdrawal form').validator('destroy') - $('#withdrawal form').validator(custom: validators, errors: errors, delay: 1200) - $('#withdrawal').show() - $('#amount').focus() - ) - -updateUser = -> - data = $('#keys form').serializeObject() - delete data['key'] - - $.post("/#{g.user.username}", data, -> - $.ajax( - url: "#{g.api}/wallets/#{g.user.username}" - type: 'DELETE' - ).always(-> - $.ajax( - url: "#{g.api}/wallets/hd/#{g.user.username}" - type: 'DELETE' - ).always(-> - getUser() - ) - ) - ) - -sendTransaction = -> - if g.key and not (typeof g.key.d is 'undefined' and typeof g.key.keyPair.d is 'undefined') - dialog = new BootstrapDialog( - title: '<h3>Confirm Transaction</h3>' - message: '<i class="fa fa-spinner fa-spin"></i> Calculating fee...</i>' - buttons: [ - label: 'Send' - cssClass: 'btn-primary' - , - label: ' Cancel' - cssClass: 'btn-default' - action: (dialogItself) -> dialogItself.close() - icon: 'glyphicon glyphicon-ban-circle' - ] - ).open() - - params = - inputs: [{wallet_name: g.user.username, wallet_token: g.token}] - outputs: [{addresses: [$('#recipient').val()], value: 1}] - preference: $('#priority').val() - - $.post("#{g.api}/txs/new", JSON.stringify(params)).done((data) -> - if $('#currency_toggle').html() is g.user.unit - amount = $('#amount').val() - else - amount = convertedAmount() - - value = parseInt(amount * 100000000 / multiplier()) - - params.fees = data.tx.fees - params.outputs[0].value = value - if value > parseFloat(g.balance).toSatoshis() - params.fees - params.outputs[0].value -= params.fees - - $.post("#{g.api}/txs/new", JSON.stringify(params)).done((data) -> - data.pubkeys = [] - if g.key instanceof bitcoin.ECPair - data.signatures = data.tosign.map((tosign, i) -> - data.pubkeys.push(g.key.getPublicKeyBuffer().toString('hex')) - g.key.sign(new buffer.Buffer(tosign, "hex")).toDER().toString("hex") - ) - else - data.signatures = data.tosign.map((tosign, i) -> - path = data.tx.inputs[i].hd_path.split('/') - key = g.key.derive(parseInt(path[1])).derive(parseInt(path[2])) - data.pubkeys.push(key.keyPair.getPublicKeyBuffer().toString('hex')) - key.keyPair.sign(new buffer.Buffer(tosign, "hex")).toDER().toString("hex") - ) - - g.data = data - - amount = data.tx.outputs[0].value - fee = data.tx.fees - total = amount - if value > parseFloat(g.balance).toSatoshis() - data.tx.fees - total += fee - - - $('.dialog .amount').html("#{(amount.toBTC())} #{g.user.unit} (#{amount.toFiat()} #{g.user.currency})") - $('.dialog .fee').html("#{(fee.toBTC())} #{g.user.unit} (#{fee.toFiat()} #{g.user.currency})") - $('.dialog .total').html("#{(total.toBTC())} #{g.user.unit} (#{total.toFiat()} #{g.user.currency})") - $('.dialog .address').html(data.tx.outputs[0].addresses[0]) - - dialog.getModalBody().html($('.dialog').html()) - - if amount.toBTC() < 0.00000534 - displayErrors({errors: [error: 'Amount left over after fee is too small to send']}, dialog) - - dialog.getModal().find('.btn-primary').click(-> - $.post("#{g.api}/txs/send", JSON.stringify(g.data)).then((finaltx) -> - $('#transaction_sent').fadeIn() - balance = g.balance.toSatoshis() - finaltx.tx.outputs[0].value - finaltx.tx.fees - g.balance = balance.toBTC() - fiat = balance.toFiat() - $('#balance').html(g.balance) - $('#fiat').html("#{fiat} #{g.user.currency}") - $('#blockchain').off('click').on('click', -> window.open('https://blockchain.info/tx/' + finaltx.tx.hash, '_blank')) - dialog.close() - ) - ) - ).fail((data) -> - displayErrors(data.responseJSON, dialog) - ) - ).fail((data) -> - displayErrors(data.responseJSON, dialog) - ) - -displayErrors = (data, dialog) -> - if data.errors - dialog.getModalBody().html('') - dialog.getModal().find('.btn-primary').hide() - for e in data.errors - dialog.getModalBody().append("<div class='alert alert-danger'>#{e.error}</div>") - - -convertedAmount = -> - g.amount = amount unless g.amount and !isNaN(parseFloat(g.amount)) - amount = parseFloat($('#amount').val() * multiplier() / g.exchange).toFixed(precision()) - difference = parseFloat(Math.abs(g.amount - amount).toFixed(precision())) - tolerance = parseFloat((.00000002 * g.exchange * multiplier()).toFixed(precision())) - if difference > tolerance - return amount - else - return g.amount - - -check_address = (address) -> - try - bitcoin.address.fromBase58Check(address) - return true - catch - return isBip32(address) - -isBip32 = (address) -> - try - bitcoin.HDNode.fromBase58(address) - return true - catch - return false - -multiplier = -> - switch g.user.unit - when 'BTC' then 1 - when 'mBTC' then 1000 - when 'µBTC' then 1000000 - when 'bits' then 1000000 - when 'satoshis' then 100000000 - -precision = -> - 9 - multiplier().toString().length - -Number.prototype.toBTC = -> - parseFloat((this / 100000000 * multiplier())).toFixed(precision()) - -Number.prototype.toFiat = -> - parseFloat((this * g.exchange / 100000000)).toFixed(2) - -Number.prototype.toSatoshis = -> - parseInt(this * 100000000 / multiplier()) - - |
