EXCHANGE_FAIL = "Problem fetching exchange rate"
SOCKET_FAIL = "Problem connecting to payment server, notifications may not appear"
ADDRESS_FAIL = "Invalid address"
API_URL = "wss://socket.blockcypher.com/v1/btc/main"
TEST_URL = "wss://socket.blockcypher.com/v1/btc/test3"
g = exports ? this
g.errors = []
g.amount_requested = 0
g.amount = 0.toFixed(2)
g.tip = 1
g.transactions = []
$(->
$.ajax(
url: $('#user').val() + '.json',
dataType: 'json',
success: (data) ->
g.user = data
setup()
)
$('button').click((e) ->
e.preventDefault()
)
$('.numpad .btn').off('click').click((e) ->
e.preventDefault()
m = $(this).html()
n = parseFloat($('.amount').html())
if m is 'C'
g.amount = 0.toFixed(2)
updateTotal()
return
return if n > 10000000
if m is '00'
n = 100 * n
else
n = 10 * n + parseFloat(m) / 100
g.amount = n.toFixed(2)
updateTotal()
)
$('.numpad .btn:last').off('click').click((e) ->
e.preventDefault()
g.amount = (Math.floor(100 * (parseFloat($('.amount').html()) / 10)) / 100).toFixed(2)
updateTotal()
)
$('.tippad .btn').off('click').click((e) ->
e.preventDefault()
text = $(this).html()
if text is 'No Tip'
value = 0
else
value = text.slice(1, -1)
$(this).addClass('active')
$(this).siblings().removeClass('active')
g.tip = 1 + (parseFloat(value)/100)
updateTotal()
)
$('#received').click(-> window.location = "/#{g.user.username}/report")
$('#slide').click(->
$('#controls').slideToggle()
$(this).find('i').toggleClass('fa-sort-up').toggleClass('fa-sort-down')
)
)
setup = ->
g.user.address or= ''
g.user.commission or= 0
g.user.currency or= 'CAD'
g.user.symbol or= 'quadrigacx'
g.user.unit or= 'BTC'
if g.user.title
$('#title').html("#{g.user.title}").show()
if g.user.logo
ext = g.user.logo.substr(g.user.logo.length - 3)
src = "/img/logos/#{g.user.username}.#{ext}"
$('#logo').attr('src', src).show()
getAddress()
if g.user.address[0] is 'm'
API_URL = TEST_URL
$('.symbol').html(g.user.currency)
$('.currency').html(g.user.currency)
$('.unit').html(g.user.unit)
$('#received').hide()
fetchExchangeRate()
listen()
fetchExchangeRate = ->
$.ajax(
url: "ticker?currency=#{g.user.currency}&symbol=#{g.user.symbol}&type=bid",
success: (exchange) ->
if exchange?
clear(EXCHANGE_FAIL)
else
fail(EXCHANGE_FAIL)
return
g.exchange = (exchange - exchange * g.user.commission * 0.01).toFixed(2)
$('#exchange').html(g.exchange)
updateTotal()
unless g.setupComplete
g.setupComplete = true
error: -> fail(EXCHANGE_FAIL)
)
setTimeout(fetchExchangeRate, 900000)
updateTotal = ->
precision = 9 - multiplier().toString().length
subtotal = parseFloat(g.amount * g.tip).toFixed(2)
total = (subtotal * multiplier() / g.exchange).toFixed(precision)
g.amount_requested = (subtotal / g.exchange).toFixed(8)
unless $.isNumeric(total)
total = ''
$('#received').hide()
$('#payment').fadeIn('slow')
$('.tip').html((subtotal - g.amount).toFixed(2))
$('.subtotal').html(subtotal.toString())
$('.amount').html(g.amount)
$('.exchange').html(g.exchange)
$('.symbol').html(g.user.symbol)
if g.user.commission < 0
$('.commission').html("+#{Math.abs(g.user.commission)}%")
$('#total').html(total.toString())
size = 300
$('#qr').css('height', size)
time = 0
if g.timeout
time = 10
clearTimeout(g.timeout)
g.timeout = setTimeout(->
$('#qr').html('')
new QRCode('qr',
text: "bitcoin:#{g.user.address}?amount=#{g.amount_requested.toString()}"
width: size
height: size
)
, time)
listen = ->
g.attempts++
if g.blockchain and g.blockchain.readyState is 1
setTimeout(listen, 12000)
else
fail(SOCKET_FAIL) if g.attempts > 3
g.blockchain = new WebSocket(API_URL)
g.blockchain.onopen = ->
if g.blockchain.readyState is 1
g.attempts = 0
clear(SOCKET_FAIL)
g.blockchain.send('{"event":"unconfirmed-tx", "address":"' + g.user.address + '"}')
else
setTimeout(g.blockchain.onopen, 12000 * g.attempts)
g.blockchain.onerror = ->
fail(SOCKET_FAIL)
g.blockchain.close()
delete g.blockchain
listen()
g.blockchain.onclose = ->
delete g.blockchain
listen()
g.blockchain.onmessage = (e) ->
tx = JSON.parse(e.data)
amount = 0
return if tx.hash == g.last_seen
g.last_seen = tx.hash
for output in tx.outputs
if (output.addresses[0] == g.user.address)
amount += output.value / 100000000
logTransaction(tx.hash, amount)
logTransaction = (txid, amount) ->
if $('#received').is(":hidden") and amount >= g.amount_requested
$('#payment').hide()
$('#received').fadeIn('slow')
$('#success')[0].play()
g.user.index++
if g.transactions.indexOf(txid) is -1
g.transactions.push(txid)
$.post("/#{g.user.username}/transactions",
txid: txid,
address: g.user.address,
date: moment().format("YYYY-MM-DD HH:mm:ss"),
received: amount,
exchange: g.exchange
tip: g.tip
)
getAddress()
getAddress = ->
try
bitcoin.address.fromBase58Check(g.user.pubkey)
g.user.address = g.user.pubkey
catch
master = bitcoin.HDNode.fromBase58(g.user.pubkey)
child = master.derive(0).derive(g.user.index)
g.user.address = child.getAddress().toString()
g.blockchain.close() if g.blockchain
listen()
$('#address').html("#{g.user.address}")
fail = (msg) ->
g.errors.push(msg)
g.errors = g.errors.uniq()
$('#error').show().html(g.errors.toString())
clear = (msg) ->
i = g.errors.indexOf(msg)
g.errors.splice(i, 1) if i >= 0
if (g.errors.length > 0)
$('#error').show().html(g.errors.toString())
else
$('#error').hide()
$('#calculator').fadeIn('slow')
Array::uniq = ->
output = {}
output[@[key]] = @[key] for key in [0...@length]
value for key, value of output
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