You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
6.3 KiB
170 lines
6.3 KiB
from typing import TYPE_CHECKING
|
|
|
|
from kivy.lang import Builder
|
|
from kivy.factory import Factory
|
|
|
|
from electrum.gui.kivy.i18n import _
|
|
from electrum.lnaddr import lndecode
|
|
from electrum.util import bh2u
|
|
from electrum.bitcoin import COIN
|
|
import electrum.simple_config as config
|
|
|
|
from .label_dialog import LabelDialog
|
|
|
|
if TYPE_CHECKING:
|
|
from ...main_window import ElectrumWindow
|
|
|
|
|
|
Builder.load_string('''
|
|
<LightningOpenChannelDialog@Popup>
|
|
id: s
|
|
name: 'lightning_open_channel'
|
|
title: _('Open Lightning Channel')
|
|
pubkey: ''
|
|
amount: ''
|
|
ipport: ''
|
|
BoxLayout
|
|
spacing: '12dp'
|
|
padding: '12dp'
|
|
orientation: 'vertical'
|
|
SendReceiveBlueBottom:
|
|
id: blue_bottom
|
|
size_hint: 1, None
|
|
height: self.minimum_height
|
|
BoxLayout:
|
|
size_hint: 1, None
|
|
height: blue_bottom.item_height
|
|
Image:
|
|
source: 'atlas://electrum/gui/kivy/theming/light/globe'
|
|
size_hint: None, None
|
|
size: '22dp', '22dp'
|
|
pos_hint: {'center_y': .5}
|
|
BlueButton:
|
|
text: s.pubkey if s.pubkey else _('Node ID')
|
|
shorten: True
|
|
#CardSeparator:
|
|
# color: blue_bottom.foreground_color
|
|
#BoxLayout:
|
|
# size_hint: 1, None
|
|
# height: blue_bottom.item_height
|
|
# Image:
|
|
# source: 'atlas://electrum/gui/kivy/theming/light/network'
|
|
# size_hint: None, None
|
|
# size: '22dp', '22dp'
|
|
# pos_hint: {'center_y': .5}
|
|
# BlueButton:
|
|
# text: s.ipport if s.ipport else _('host:port')
|
|
# on_release: s.ipport_dialog()
|
|
CardSeparator:
|
|
color: blue_bottom.foreground_color
|
|
BoxLayout:
|
|
size_hint: 1, None
|
|
height: blue_bottom.item_height
|
|
Image:
|
|
source: 'atlas://electrum/gui/kivy/theming/light/calculator'
|
|
size_hint: None, None
|
|
size: '22dp', '22dp'
|
|
pos_hint: {'center_y': .5}
|
|
BlueButton:
|
|
text: s.amount if s.amount else _('Amount')
|
|
on_release: app.amount_dialog(s, True)
|
|
BoxLayout:
|
|
size_hint: 1, None
|
|
IconButton:
|
|
icon: 'atlas://electrum/gui/kivy/theming/light/copy'
|
|
size_hint: 0.5, None
|
|
height: '48dp'
|
|
on_release: s.do_paste()
|
|
IconButton:
|
|
icon: 'atlas://electrum/gui/kivy/theming/light/camera'
|
|
size_hint: 0.5, None
|
|
height: '48dp'
|
|
on_release: app.scan_qr(on_complete=s.on_qr)
|
|
Button:
|
|
text: _('Suggest')
|
|
size_hint: 1, None
|
|
height: '48dp'
|
|
on_release: s.choose_node()
|
|
Button:
|
|
text: _('Open')
|
|
size_hint: 1, None
|
|
height: '48dp'
|
|
on_release: s.open_channel()
|
|
Widget:
|
|
size_hint: 1, 1
|
|
''')
|
|
|
|
class LightningOpenChannelDialog(Factory.Popup):
|
|
def ipport_dialog(self):
|
|
def callback(text):
|
|
self.ipport = text
|
|
d = LabelDialog(_('IP/port in format:\n[host]:[port]'), self.ipport, callback)
|
|
d.open()
|
|
|
|
def choose_node(self):
|
|
suggested = self.app.wallet.lnworker.suggest_peer()
|
|
if suggested:
|
|
self.pubkey = suggested.hex()
|
|
|
|
def __init__(self, app, lnaddr=None, msg=None):
|
|
super(LightningOpenChannelDialog, self).__init__()
|
|
self.app = app # type: ElectrumWindow
|
|
self.lnaddr = lnaddr
|
|
self.msg = msg
|
|
|
|
def open(self, *args, **kwargs):
|
|
super(LightningOpenChannelDialog, self).open(*args, **kwargs)
|
|
if self.lnaddr:
|
|
fee = self.app.electrum_config.fee_per_kb()
|
|
if not fee:
|
|
fee = config.FEERATE_FALLBACK_STATIC_FEE
|
|
self.amount = self.app.format_amount_and_units(self.lnaddr.amount * COIN + fee * 2)
|
|
self.pubkey = bh2u(self.lnaddr.pubkey.serialize())
|
|
if self.msg:
|
|
self.app.show_info(self.msg)
|
|
|
|
def do_paste(self):
|
|
contents = self.app._clipboard.paste()
|
|
if not contents:
|
|
self.app.show_info(_("Clipboard is empty"))
|
|
return
|
|
self.pubkey = contents
|
|
|
|
def on_qr(self, conn_str):
|
|
self.pubkey = conn_str
|
|
|
|
# FIXME "max" button in amount_dialog should enforce LN_MAX_FUNDING_SAT
|
|
def open_channel(self):
|
|
if not self.pubkey or not self.amount:
|
|
self.app.show_info(_('All fields must be filled out'))
|
|
return
|
|
conn_str = self.pubkey
|
|
if self.ipport:
|
|
conn_str += '@' + self.ipport.strip()
|
|
amount = self.app.get_amount(self.amount)
|
|
self.app.protected('Enter PIN to create a new channel', self.do_open_channel, (conn_str, amount))
|
|
self.dismiss()
|
|
|
|
def do_open_channel(self, conn_str, amount, password):
|
|
coins = self.app.wallet.get_spendable_coins(None, nonlocal_only=True)
|
|
funding_tx = self.app.wallet.lnworker.mktx_for_open_channel(coins=coins, funding_sat=amount)
|
|
try:
|
|
chan, funding_tx = self.app.wallet.lnworker.open_channel(connect_str=conn_str,
|
|
funding_tx=funding_tx,
|
|
funding_sat=amount,
|
|
push_amt_sat=0,
|
|
password=password)
|
|
except Exception as e:
|
|
self.app.show_error(_('Problem opening channel: ') + '\n' + repr(e))
|
|
return
|
|
n = chan.constraints.funding_txn_minimum_depth
|
|
message = '\n'.join([
|
|
_('Channel established.'),
|
|
_('Remote peer ID') + ':' + chan.node_id.hex(),
|
|
_('This channel will be usable after {} confirmations').format(n)
|
|
])
|
|
if not funding_tx.is_complete():
|
|
message += '\n\n' + _('Please sign and broadcast the funding transaction')
|
|
self.app.show_info(message)
|
|
if not funding_tx.is_complete():
|
|
self.app.tx_dialog(funding_tx)
|
|
|