diff --git a/gui/forms.py b/gui/forms.py
index 56bdee7..6f9fc53 100644
--- a/gui/forms.py
+++ b/gui/forms.py
@@ -39,8 +39,8 @@ class CloseChannelForm(forms.Form):
force = forms.BooleanField(widget=forms.CheckboxSelectMultiple, required=False)
class ConnectPeerForm(forms.Form):
- peer_pubkey = forms.CharField(label='funding_txid', max_length=66)
- host = forms.CharField(label='funding_txid', max_length=120)
+ peer_pubkey = forms.CharField(label='peer_pubkey', max_length=66)
+ host = forms.CharField(label='host', max_length=120)
class AddInvoiceForm(forms.Form):
value = forms.IntegerField(label='value')
diff --git a/gui/rebalancer.py b/gui/rebalancer.py
index 39f7cad..34d9a02 100644
--- a/gui/rebalancer.py
+++ b/gui/rebalancer.py
@@ -107,7 +107,7 @@ def auto_schedule():
else:
LocalSettings(key='AR-Inbound%', value='0.85').save()
inbound_percent = 0.85 * 100
- outbound_cans = list(auto_rebalance_channels.filter(percent_outbound__gte=outbound_percent).values_list('chan_id', flat=True))
+ outbound_cans = list(auto_rebalance_channels.filter(auto_rebalance=False, percent_outbound__gte=outbound_percent).values_list('chan_id', flat=True))
inbound_cans = auto_rebalance_channels.filter(auto_rebalance=True, percent_inbound__gte=inbound_percent)
if len(inbound_cans) > 0 and len(outbound_cans) > 0:
if LocalSettings.objects.filter(key='AR-Target%').exists():
diff --git a/gui/serializers.py b/gui/serializers.py
index 406d1cd..86c054b 100644
--- a/gui/serializers.py
+++ b/gui/serializers.py
@@ -35,4 +35,22 @@ class RebalancerSerializer(serializers.HyperlinkedModelSerializer):
status = serializers.ReadOnlyField()
class Meta:
model = Rebalancer
- exclude = []
\ No newline at end of file
+ exclude = []
+
+class ConnectPeerSerializer(serializers.Serializer):
+ peer_pubkey = serializers.CharField(label='peer_pubkey', max_length=66)
+ host = serializers.CharField(label='host', max_length=120)
+
+class OpenChannelSerializer(serializers.Serializer):
+ peer_pubkey = serializers.CharField(label='peer_pubkey', max_length=66)
+ local_amt = serializers.IntegerField(label='local_amt')
+ sat_per_byte = serializers.IntegerField(label='sat_per_btye')
+
+class CloseChannelSerializer(serializers.Serializer):
+ funding_txid = serializers.CharField(label='funding_txid', max_length=64)
+ output_index = serializers.IntegerField(label='output_index')
+ target_fee = serializers.IntegerField(label='target_fee')
+ force = serializers.BooleanField(default=False)
+
+class AddInvoiceSerializer(serializers.Serializer):
+ value = serializers.IntegerField(label='value')
\ No newline at end of file
diff --git a/gui/templates/home.html b/gui/templates/home.html
index 011880c..1865c51 100644
--- a/gui/templates/home.html
+++ b/gui/templates/home.html
@@ -351,7 +351,7 @@
-
+
@@ -366,7 +366,7 @@
-
+
@@ -417,7 +417,7 @@
-
+
diff --git a/gui/urls.py b/gui/urls.py
index 83b26e9..62cd321 100644
--- a/gui/urls.py
+++ b/gui/urls.py
@@ -13,13 +13,18 @@ urlpatterns = [
path('', views.home, name='home'),
path('route', views.route, name='route'),
path('peers', views.peers, name='peers'),
- path('openchannel/', views.open_channel, name='open-channel'),
- path('closechannel/', views.close_channel, name='close-channel'),
- path('connectpeer/', views.connect_peer, name='connect-peer'),
- path('newaddress/', views.new_address, name='new-address'),
- path('createinvoice/', views.add_invoice, name='add-invoice'),
+ path('openchannel/', views.open_channel_form, name='open-channel-form'),
+ path('closechannel/', views.close_channel_form, name='close-channel-form'),
+ path('connectpeer/', views.connect_peer_form, name='connect-peer-form'),
+ path('newaddress/', views.new_address_form, name='new-address-form'),
+ path('createinvoice/', views.add_invoice_form, name='add-invoice-form'),
path('rebalancer/', views.rebalance, name='rebalancer'),
path('updatechanpolicy/', views.update_chan_policy, name='updatechanpolicy'),
path('autorebalance/', views.auto_rebalance, name='auto-rebalance'),
path('api/', include(router.urls), name='api-root'),
+ path('api/connectpeer/', views.connect_peer, name='connect-peer'),
+ path('api/openchannel/', views.open_channel, name='open-channel'),
+ path('api/closechannel/', views.close_channel, name='close-channel'),
+ path('api/createinvoice/', views.add_invoice, name='add-invoice'),
+ path('api/newaddress/', views.new_address, name='new-address'),
]
diff --git a/gui/views.py b/gui/views.py
index 209595e..29ffeea 100644
--- a/gui/views.py
+++ b/gui/views.py
@@ -3,13 +3,13 @@ from django.contrib import messages
from django.shortcuts import render, redirect
from django.db.models import Sum
from rest_framework import viewsets
+from rest_framework.response import Response
+from rest_framework.decorators import api_view
from .forms import OpenChannelForm, CloseChannelForm, ConnectPeerForm, AddInvoiceForm, RebalancerForm, ChanPolicyForm, AutoRebalanceForm
from .models import Payments, PaymentHops, Invoices, Forwards, Channels, Rebalancer, LocalSettings
-from .serializers import PaymentSerializer, InvoiceSerializer, ForwardSerializer, ChannelSerializer, RebalancerSerializer
+from .serializers import ConnectPeerSerializer, OpenChannelSerializer, CloseChannelSerializer, AddInvoiceSerializer, PaymentSerializer, InvoiceSerializer, ForwardSerializer, ChannelSerializer, RebalancerSerializer
from . import rpc_pb2 as ln
from . import rpc_pb2_grpc as lnrpc
-from . import router_pb2 as lnr
-from . import router_pb2_grpc as lnrouter
#Define lnd connection for repeated use
def lnd_connect():
@@ -50,7 +50,7 @@ def home(request):
total_invoices = Invoices.objects.filter(state=1).count()
total_received = 0 if total_invoices == 0 else Invoices.objects.aggregate(Sum('amt_paid'))['amt_paid__sum']
#Get recorded forwarding events
- forwards = Forwards.objects.all().order_by('-forward_date')
+ forwards = Forwards.objects.all().order_by('-id')
total_forwards = Forwards.objects.count()
total_value_forwards = 0 if total_forwards == 0 else int(Forwards.objects.aggregate(Sum('amt_out_msat'))['amt_out_msat__sum']/1000)
total_earned = 0 if total_forwards == 0 else Forwards.objects.aggregate(Sum('fee'))['fee__sum']
@@ -146,7 +146,7 @@ def peers(request):
else:
return redirect('home')
-def open_channel(request):
+def open_channel_form(request):
if request.method == 'POST':
form = OpenChannelForm(request.POST)
if form.is_valid():
@@ -169,7 +169,7 @@ def open_channel(request):
else:
return redirect('home')
-def close_channel(request):
+def close_channel_form(request):
if request.method == 'POST':
form = CloseChannelForm(request.POST)
if form.is_valid():
@@ -192,7 +192,7 @@ def close_channel(request):
break
except Exception as e:
error = str(e)
- messages.error(request, 'Channel creation failed! Error: ' + error)
+ messages.error(request, 'Channel close failed! Error: ' + error)
return redirect('home')
else:
messages.error(request, 'Invalid Request. Please try again.')
@@ -200,7 +200,7 @@ def close_channel(request):
else:
return redirect('home')
-def connect_peer(request):
+def connect_peer_form(request):
if request.method == 'POST':
form = ConnectPeerForm(request.POST)
if form.is_valid():
@@ -223,7 +223,7 @@ def connect_peer(request):
else:
return redirect('home')
-def new_address(request):
+def new_address_form(request):
if request.method == 'POST':
try:
stub = lnrpc.LightningStub(lnd_connect())
@@ -236,9 +236,9 @@ def new_address(request):
else:
return redirect('home')
-def add_invoice(request):
+def add_invoice_form(request):
if request.method == 'POST':
- form = AddInvoice(request.POST)
+ form = AddInvoiceForm(request.POST)
if form.is_valid():
try:
stub = lnrpc.LightningStub(lnd_connect())
@@ -412,4 +412,90 @@ class RebalancerViewSet(viewsets.ReadOnlyModelViewSet):
return redirect('api-root')
else:
print(serializer.errors)
- return redirect('api-root')
\ No newline at end of file
+ return redirect('api-root')
+
+@api_view(['POST'])
+def connect_peer(request):
+ serializer = ConnectPeerSerializer(data=request.data)
+ if serializer.is_valid():
+ try:
+ stub = lnrpc.LightningStub(lnd_connect())
+ peer_pubkey = serializer.validated_data['peer_pubkey']
+ host = serializer.validated_data['host']
+ ln_addr = ln.LightningAddress()
+ ln_addr.pubkey = peer_pubkey
+ ln_addr.host = host
+ response = stub.ConnectPeer(ln.ConnectPeerRequest(addr=ln_addr))
+ return Response({'message': 'Connection successful! ' + str(response)})
+ except Exception as e:
+ error = str(e)
+ return Response({'error': 'Connection request failed! Error: ' + error})
+ else:
+ return Response({'error': 'Invalid request!'})
+
+@api_view(['POST'])
+def open_channel(request):
+ serializer = OpenChannelSerializer(data=request.data)
+ if serializer.is_valid():
+ try:
+ stub = lnrpc.LightningStub(lnd_connect())
+ pubkey_bytes = bytes.fromhex(serializer.validated_data['peer_pubkey'])
+ for response in stub.OpenChannel(ln.OpenChannelRequest(node_pubkey=pubkey_bytes, local_funding_amount=serializer.validated_data['local_amt'], sat_per_byte=serializer.validated_data['sat_per_byte'])):
+ return Response({'message': 'Channel created! Funding TXID: ' + str(response.chan_pending.txid[::-1].hex()) + ':' + str(response.chan_pending.output_index)})
+ except Exception as e:
+ error = str(e)
+ details_index = error.find('details =') + 11
+ debug_error_index = error.find('debug_error_string =') - 3
+ error_msg = error[details_index:debug_error_index]
+ return Response({'error': 'Channel creation failed! Error: ' + error_msg})
+ else:
+ return Response({'error': 'Invalid request!'})
+
+@api_view(['POST'])
+def close_channel(request):
+ serializer = CloseChannelSerializer(data=request.data)
+ if serializer.is_valid():
+ try:
+ stub = lnrpc.LightningStub(lnd_connect())
+ funding_txid = serializer.validated_data['funding_txid']
+ output_index = serializer.validated_data['output_index']
+ target_fee = serializer.validated_data['target_fee']
+ channel_point = ln.ChannelPoint()
+ channel_point.funding_txid_bytes = bytes.fromhex(funding_txid)
+ channel_point.funding_txid_str = funding_txid
+ channel_point.output_index = output_index
+ if serializer.validated_data['force']:
+ for response in stub.CloseChannel(ln.CloseChannelRequest(channel_point=channel_point, force=True)):
+ return Response({'message': 'Channel force closed! Closing TXID: ' + str(response.close_pending.txid[::-1].hex()) + ':' + str(response.close_pending.output_index)})
+ else:
+ for response in stub.CloseChannel(ln.CloseChannelRequest(channel_point=channel_point, sat_per_byte=target_fee)):
+ return Response({'message': 'Channel gracefully closed! Closing TXID: ' + str(response.close_pending.txid[::-1].hex()) + ':' + str(response.close_pending.output_index)})
+ except Exception as e:
+ error = str(e)
+ return Response({'error': 'Channel close failed! Error: ' + error})
+ else:
+ return Response({'error': 'Invalid request!'})
+
+@api_view(['POST'])
+def add_invoice(request):
+ serializer = AddInvoiceSerializer(data=request.data)
+ if serializer.is_valid() and serializer.validated_data['value'] >= 0:
+ try:
+ stub = lnrpc.LightningStub(lnd_connect())
+ response = stub.AddInvoice(ln.Invoice(value=serializer.validated_data['value']))
+ return Response({'message': 'Invoice created!', 'data':str(response.payment_request)})
+ except Exception as e:
+ error = str(e)
+ return Response({'error': 'Invoice creation failed! Error: ' + error})
+ else:
+ return Response({'error': 'Invalid request!'})
+
+@api_view(['POST'])
+def new_address(request):
+ try:
+ stub = lnrpc.LightningStub(lnd_connect())
+ response = stub.NewAddress(ln.NewAddressRequest(type=0))
+ return Response({'message': 'Retrieved new deposit address!', 'data':str(response.address)})
+ except Exception as e:
+ error = str(e)
+ return Response({'error': 'Address creation failed! Error: ' + error})
\ No newline at end of file