nullcount/rain

Cost aware rebalancing - prerequisites

Closed this issue · 1 comments

Currently, each node to open channels with has a dedicated loop-out operator assigned to it. This makes sense when the loop-out operator is also the node you're sharing channels with. However, if connected to a non-loop-out node, different loop-out operators may be cheaper at different times (depending on liquidity in farther hops).

It would be great if every channel could calculate the costs of looping out via every possible loop-out method.

  • each loop out operator needs a method to calculate the fees associated with a loop out of X satoshis. It should return the fees associated with the operator itself that cannot be gleaned from the P2P network graph, or miner fees alone. (e.x. kraken charges 1000sat flat fee for onchain widthdawls and deezy charges a ppm rate plus whatever onchain fee is chosen)

  • LND needs a new method for probing invoices to calculate the network fee before sending payment

These can be combined in the channel manager to calculate the fee of a loop-out before engaging. Another issue will track the actual implementation in the strategy.

import grpc
from lnd import lnrpc_pb2, lnrpc_pb2_grpc

def pay_invoice_with_invalid_hash(invoice: str, lnd_grpc_address: str, macaroon_path: str):
    # Create a gRPC channel to the LND node
    with open(macaroon_path, 'rb') as f:
        macaroon_bytes = f.read()
    macaroon = macaroon_bytes.hex()
    creds = grpc.ssl_channel_credentials()
    channel = grpc.secure_channel(lnd_grpc_address, creds)
    stub = lnrpc_pb2_grpc.LightningStub(channel)

    # Create a request to pay the invoice
    request = lnrpc_pb2.SendRequest(payment_request=invoice)

    # Add an invalid payment hash to the request
    request.payment_hash = b'\x01' * 32

    # Send the request to pay the invoice
    try:
        response = stub.SendPaymentSync(request)
    except grpc.RpcError as e:
        if e.code() == grpc.StatusCode.INVALID_ARGUMENT:
            print('Payment failed: Invalid payment hash')
            return None
        else:
            raise e

    # Return the path of hops used if the payment succeeded
    return response.route.hops