138 lines
3.8 KiB
Ruby
138 lines
3.8 KiB
Ruby
require "rqrcode"
|
|
require "lnurl"
|
|
|
|
class Services::LightningController < ApplicationController
|
|
before_action :authenticate_user!
|
|
before_action :authenticate_with_lndhub
|
|
before_action :set_current_section
|
|
before_action :fetch_balance
|
|
|
|
def index
|
|
@wallet_url = "lndhub://#{current_user.ln_account}:#{current_user.ln_password}@#{ENV['LNDHUB_PUBLIC_URL']}"
|
|
initialize_lndhub_qr_code
|
|
end
|
|
|
|
def transactions
|
|
@transactions = fetch_transactions
|
|
end
|
|
|
|
def qr_lnurlp
|
|
respond_to do |format|
|
|
lnurlp_url = "https://kosmos.org/.well-known/lnurlp/#{current_user.cn}"
|
|
lnurlp_bech32 = Lnurl.new(lnurlp_url).to_bech32
|
|
qr_code = RQRCode::QRCode.new("lightning:" + lnurlp_bech32)
|
|
|
|
format.svg do
|
|
qr_svg = qr_code.as_svg(
|
|
color: "000",
|
|
shape_rendering: "crispEdges",
|
|
module_size: 6,
|
|
standalone: true,
|
|
use_path: true,
|
|
svg_attributes: {
|
|
class: 'inline-block'
|
|
}
|
|
)
|
|
send_data(
|
|
qr_svg,
|
|
filename: "bitcoin-lightning-#{current_user.address}.svg",
|
|
type: "image/svg+xml"
|
|
)
|
|
end
|
|
format.png do
|
|
qr_png = qr_code.as_png(
|
|
fill: "white",
|
|
color: "black",
|
|
size: 1024,
|
|
)
|
|
send_data(
|
|
qr_png,
|
|
filename: "bitcoin-lightning-#{current_user.address}.png",
|
|
type: "image/png"
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def initialize_lndhub_qr_code
|
|
qr_code = RQRCode::QRCode.new(@wallet_url)
|
|
@lndhub_qr_svg = qr_code.as_svg(
|
|
color: "000",
|
|
shape_rendering: "crispEdges",
|
|
module_size: 6,
|
|
standalone: true,
|
|
use_path: true,
|
|
svg_attributes: {
|
|
class: 'inline-block'
|
|
}
|
|
)
|
|
end
|
|
|
|
def authenticate_with_lndhub(options={})
|
|
if session[:ln_auth_token].present? && !options[:force_reauth]
|
|
@ln_auth_token = session[:ln_auth_token]
|
|
else
|
|
lndhub = Lndhub.new
|
|
auth_token = lndhub.authenticate(current_user)
|
|
session[:ln_auth_token] = auth_token
|
|
@ln_auth_token = auth_token
|
|
end
|
|
rescue => e
|
|
Sentry.capture_exception(e) if Setting.sentry_enabled?
|
|
end
|
|
|
|
def set_current_section
|
|
@current_section = :services
|
|
end
|
|
|
|
def fetch_balance
|
|
lndhub = Lndhub.new
|
|
data = lndhub.balance @ln_auth_token
|
|
@balance = data["BTC"]["AvailableBalance"] rescue nil
|
|
rescue AuthError
|
|
authenticate_with_lndhub(force_reauth: true)
|
|
raise if @fetch_balance_retried
|
|
@fetch_balance_retried = true
|
|
fetch_balance
|
|
end
|
|
|
|
def fetch_transactions
|
|
lndhub = Lndhub.new
|
|
txs = lndhub.gettxs @ln_auth_token
|
|
invoices = lndhub.getuserinvoices(@ln_auth_token).select{|i| i["ispaid"]}
|
|
process_transactions(txs + invoices)
|
|
rescue AuthError
|
|
authenticate_with_lndhub(force_reauth: true)
|
|
raise if @fetch_transactions_retried
|
|
@fetch_transactions_retried = true
|
|
fetch_transactions
|
|
end
|
|
|
|
def process_transactions(txs)
|
|
txs.collect do |tx|
|
|
if tx["type"] == "bitcoind_tx"
|
|
tx["amount_sats"] = (tx["amount"] * 100000000).to_i
|
|
tx["datetime"] = Time.at(tx["time"].to_i)
|
|
tx["title"] = "Received"
|
|
tx["description"] = "On-chain topup"
|
|
tx["received"] = true
|
|
else
|
|
tx["amount_sats"] = tx["value"] || tx["amt"]
|
|
tx["fee"] = tx["type"] == "paid_invoice" ? tx["fee"] : nil
|
|
tx["datetime"] = Time.at(tx["timestamp"].to_i)
|
|
tx["title"] = tx["type"] == "paid_invoice" ? "Sent" : "Received"
|
|
tx["description"] = tx["memo"] || tx["description"]
|
|
tx["received"] = tx["type"] == "user_invoice"
|
|
end
|
|
end
|
|
|
|
# Handle an edge case where lndhub.go includes a failed payment in the
|
|
# list, which wasn't actually booked
|
|
txs.reject!{ |tx| tx["type"] == "paid_invoice" && tx["payment_preimage"].blank? }
|
|
|
|
txs.sort{ |a,b| b["datetime"] <=> a["datetime"] }
|
|
end
|
|
end
|