<filename>feeadjuster/test_feeadjuster.py
import os
import random
import string

import unittest
from pyln.testing.fixtures import *  # noqa: F401,F403
from pyln.testing.utils import DEVELOPER, wait_for


plugin_path = os.path.join(os.path.dirname(__file__), "feeadjuster.py")


def test_feeadjuster_starts(node_factory):
    l1 = node_factory.get_node()
    # Test dynamically
    l1.rpc.plugin_start(plugin_path)
    l1.daemon.wait_for_log("Plugin feeadjuster initialized.*")
    l1.rpc.plugin_stop(plugin_path)
    l1.rpc.plugin_start(plugin_path)
    l1.daemon.wait_for_log("Plugin feeadjuster initialized.*")
    l1.stop()
    # Then statically
    l1.daemon.opts["plugin"] = plugin_path
    l1.start()
    # Start at 0 and 're-await' the two inits above. Otherwise this is flaky.
    l1.daemon.logsearch_start = 0
    l1.daemon.wait_for_logs(["Plugin feeadjuster initialized.*",
                             "Plugin feeadjuster initialized.*",
                             "Plugin feeadjuster initialized.*"])
    l1.rpc.plugin_stop(plugin_path)

    # We adjust fees in init
    l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True)
    scid_A = l2.rpc.listpeers(
        l1.info["id"])["peers"][0]["channels"][0]["short_channel_id"]
    scid_B = l2.rpc.listpeers(
        l3.info["id"])["peers"][0]["channels"][0]["short_channel_id"]
    l2.rpc.plugin_start(plugin_path)
    l2.daemon.wait_for_logs([f"Adjusted fees of {scid_A}.*",
                             f"Adjusted fees of {scid_B}.*"])


def get_chan_fees(l, scid):
    for half in l.rpc.listchannels(scid)["channels"]:
        if l.info["id"] == half["source"]:
            return (half["base_fee_millisatoshi"], half["fee_per_millionth"])


def wait_for_fees(l, scids, fees):
    for scid in scids:
        wait_for(lambda: get_chan_fees(l, scid) == fees)


def wait_for_not_fees(l, scids, fees):
    for scid in scids:
        wait_for(lambda: not get_chan_fees(l, scid) == fees)


def pay(l, ll, amount):
    label = ''.join(random.choices(string.ascii_letters, k=20))
    invoice = ll.rpc.invoice(amount, label, "desc")
    route = l.rpc.getroute(ll.info["id"], amount, riskfactor=0, fuzzpercent=0)
    l.rpc.sendpay(route["route"], invoice["payment_hash"], payment_secret=invoice.get('payment_secret'))
    l.rpc.waitsendpay(invoice["payment_hash"])


def sync_gossip(nodes, scids):
    node = nodes[0]
    nodes = nodes[1:]
    for scid in scids:
        for n in nodes:
            wait_for(lambda: node.rpc.listchannels(scid) == n.rpc.listchannels(scid))


@unittest.skipIf(not DEVELOPER, "Too slow without fast gossip")
def test_feeadjuster_adjusts(node_factory):
    """
    A rather simple network:

            A                   B
    l1  <========>   l2   <=========>  l3

    l2 will adjust its configuration-set base and proportional fees for
    channels A and B as l1 and l3 exchange payments.
    """
    base_fee = 5000
    ppm_fee = 300
    l2_opts = {
        "fee-base": base_fee,
        "fee-per-satoshi": ppm_fee,
        "plugin": plugin_path,
        "feeadjuster-deactivate-fuzz": None,
    }
    l1, l2, l3 = node_factory.line_graph(3, opts=[{}, l2_opts, {}],
                                         wait_for_announce=True)

    chan_A = l2.rpc.listpeers(l1.info["id"])["peers"][0]["channels"][0]
    chan_B = l2.rpc.listpeers(l3.info["id"])["peers"][0]["channels"][0]
    scid_A = chan_A["short_channel_id"]
    scid_B = chan_B["short_channel_id"]
    nodes = [l1, l2, l3]
    scids = [scid_A, scid_B]

    # Fees don't get updated until there is a forwarding event!
    assert all([get_chan_fees(l2, scid) == (base_fee, ppm_fee)
                for scid in scids])

    chan_total = int(chan_A["total_msat"])
    assert chan_total == int(chan_B["total_msat"])

    # The first payment will trigger fee adjustment, no matter its value
    amount = int(chan_total * 0.04)
    pay(l1, l3, amount)
    wait_for(lambda: all([get_chan_fees(l2, scid) != (base_fee, ppm_fee)
                          for scid in scids]))

    # Send most of the balance to the other side..
    amount = int(chan_total * 0.8)
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([f'Adjusted fees of {scid_A} with a ratio of 0.2',
                             f'Adjusted fees of {scid_B} with a ratio of 3.'])

    # ..And back
    sync_gossip(nodes, scids)
    pay(l3, l1, amount)
    l2.daemon.wait_for_logs([f'Adjusted fees of {scid_A} with a ratio of 6.',
                             f'Adjusted fees of {scid_B} with a ratio of 0.1'])

    # Sending a payment worth 3% of the channel balance should not trigger
    # fee adjustment
    sync_gossip(nodes, scids)
    fees_before = [get_chan_fees(l2, scid) for scid in [scid_A, scid_B]]
    amount = int(chan_total * 0.03)
    pay(l1, l3, amount)
    sync_gossip(nodes, scids)
    assert fees_before == [get_chan_fees(l2, scid) for scid in scids]

    # But sending another 3%-worth payment does trigger adjustment (total sent
    # since last adjustment is >5%)
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([f'Adjusted fees of {scid_A} with a ratio of 4.',
                             f'Adjusted fees of {scid_B} with a ratio of 0.2'])


@unittest.skipIf(not DEVELOPER, "Too slow without fast gossip")
def test_feeadjuster_imbalance(node_factory):
    """
    A rather simple network:

            A                   B
    l1  <========>   l2   <=========>  l3

    l2 will adjust its configuration-set base and proportional fees for
    channels A and B as l1 and l3 exchange payments.
    """
    base_fee = 5000
    ppm_fee = 300
    l2_opts = {
        "fee-base": base_fee,
        "fee-per-satoshi": ppm_fee,
        "plugin": plugin_path,
        "feeadjuster-deactivate-fuzz": None,
        "feeadjuster-imbalance": 0.7,  # should be normalized to 30/70
    }
    l1, l2, l3 = node_factory.line_graph(3, opts=[{}, l2_opts, {}],
                                         wait_for_announce=True)

    chan_A = l2.rpc.listpeers(l1.info["id"])["peers"][0]["channels"][0]
    chan_B = l2.rpc.listpeers(l3.info["id"])["peers"][0]["channels"][0]
    scid_A = chan_A["short_channel_id"]
    scid_B = chan_B["short_channel_id"]
    scids = [scid_A, scid_B]
    default_fees = [(base_fee, ppm_fee), (base_fee, ppm_fee)]

    chan_total = int(chan_A["total_msat"])
    assert chan_total == int(chan_B["total_msat"])
    l2.daemon.wait_for_log('imbalance of 30%/70%')

    # we force feeadjust initially to test this method and check if it applies
    # default fees when balancing the channel below
    l2.rpc.feeadjust()
    l2.daemon.wait_for_logs([
        f"Adjusted fees.*{scid_A}",
        f"Adjusted fees.*{scid_B}"
    ])
    log_offset = len(l2.daemon.logs)
    wait_for_not_fees(l2, scids, default_fees[0])

    # First bring channel to somewhat of a balance
    amount = int(chan_total * 0.5)
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([
        f'Set default fees as imbalance is too low: {scid_A}',
        f'Set default fees as imbalance is too low: {scid_B}'
    ])
    wait_for_fees(l2, scids, default_fees[0])

    # Because of the 70/30 imbalance limiter, a 15% payment must not yet trigger
    # 50% + 15% = 65% .. which is < 70%
    amount = int(chan_total * 0.15)
    pay(l1, l3, amount)
    assert not l2.daemon.is_in_log("Adjusted fees", log_offset)

    # Sending another 20% must now trigger because the imbalance
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([
        f"Adjusted fees.*{scid_A}",
        f"Adjusted fees.*{scid_B}"
    ])
    wait_for_not_fees(l2, scids, default_fees[0])

    # Bringing it back must cause default fees
    pay(l3, l1, amount)
    l2.daemon.wait_for_logs([
        f'Set default fees as imbalance is too low: {scid_A}',
        f'Set default fees as imbalance is too low: {scid_B}'
    ])
    wait_for_fees(l2, scids, default_fees[0])


@unittest.skipIf(not DEVELOPER, "Too slow without fast gossip")
def test_feeadjuster_big_enough_liquidity(node_factory):
    """
    A rather simple network:

            A                   B
    l1  <========>   l2   <=========>  l3

    l2 will adjust its configuration-set base and proportional fees for
    channels A and B as l1 and l3 exchange payments.
    """
    base_fee = 5000
    ppm_fee = 300
    l2_opts = {
        "fee-base": base_fee,
        "fee-per-satoshi": ppm_fee,
        "plugin": plugin_path,
        "feeadjuster-deactivate-fuzz": None,
        "feeadjuster-imbalance": 0.5,
        "feeadjuster-enough-liquidity": "0.001btc",
        "feeadjuster-threshold-abs": "0.0001btc",
    }
    # channels' size: 0.01btc
    # between 0.001btc and 0.009btc the liquidity is big enough
    l1, l2, l3 = node_factory.line_graph(3, fundamount=10**6, opts=[{}, l2_opts, {}],
                                         wait_for_announce=True)

    chan_A = l2.rpc.listpeers(l1.info["id"])["peers"][0]["channels"][0]
    chan_B = l2.rpc.listpeers(l3.info["id"])["peers"][0]["channels"][0]
    scid_A = chan_A["short_channel_id"]
    scid_B = chan_B["short_channel_id"]
    scids = [scid_A, scid_B]
    default_fees = [(base_fee, ppm_fee), (base_fee, ppm_fee)]

    chan_total = int(chan_A["total_msat"])
    assert chan_total == int(chan_B["total_msat"])
    l2.daemon.logsearch_start = 0
    l2.daemon.wait_for_log('enough_liquidity: 100000000msat')

    # we force feeadjust initially to test this method and check if it applies
    # default fees when balancing the channel below
    l2.rpc.feeadjust()
    l2.daemon.wait_for_logs([
        f"Adjusted fees.*{scid_A}",
        f"Adjusted fees.*{scid_B}"
    ])
    wait_for_not_fees(l2, scids, default_fees[0])

    # Bring channels to beyond big enough liquidity with 0.003btc
    amount = 300000000
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([
        f"Adjusted fees of {scid_A} with a ratio of 1.0",
        f"Adjusted fees of {scid_B} with a ratio of 1.0"
    ])
    log_offset = len(l2.daemon.logs)
    wait_for_fees(l2, scids, default_fees[0])

    # Let's move another 0.003btc -> the channels will be at 0.006btc
    amount = 300000000
    pay(l1, l3, amount)
    l2.wait_for_htlcs()
    assert not l2.daemon.is_in_log("Adjusted fees", log_offset)

    # Sending another 0.0033btc will result in a channel balance of 0.0093btc
    # It must trigger because the remaining liquidity is not big enough
    amount = 330000000
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([
        f"Adjusted fees.*{scid_A}",
        f"Adjusted fees.*{scid_B}"
    ])
    wait_for_not_fees(l2, scids, default_fees[0])

<filename>feeadjuster/test_feeadjuster.py
import os
import random
import string

import unittest
from pyln.testing.fixtures import *  # noqa: F401,F403
from pyln.testing.utils import DEVELOPER, wait_for


plugin_path = os.path.join(os.path.dirname(__file__), "feeadjuster.py")


def test_feeadjuster_starts(node_factory):
    l1 = node_factory.get_node()
    # Test dynamically
    l1.rpc.plugin_start(plugin_path)
    l1.daemon.wait_for_log("Plugin feeadjuster initialized.*")
    l1.rpc.plugin_stop(plugin_path)
    l1.rpc.plugin_start(plugin_path)
    l1.daemon.wait_for_log("Plugin feeadjuster initialized.*")
    l1.stop()
    # Then statically
    l1.daemon.opts["plugin"] = plugin_path
    l1.start()
    # Start at 0 and 're-await' the two inits above. Otherwise this is flaky.
    l1.daemon.logsearch_start = 0
    l1.daemon.wait_for_logs(["Plugin feeadjuster initialized.*",
                             "Plugin feeadjuster initialized.*",
                             "Plugin feeadjuster initialized.*"])
    l1.rpc.plugin_stop(plugin_path)

    # We adjust fees in init
    l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True)
    scid_A = l2.rpc.listpeers(
        l1.info["id"])["peers"][0]["channels"][0]["short_channel_id"]
    scid_B = l2.rpc.listpeers(
        l3.info["id"])["peers"][0]["channels"][0]["short_channel_id"]
    l2.rpc.plugin_start(plugin_path)
    l2.daemon.wait_for_logs([f"Adjusted fees of {scid_A}.*",
                             f"Adjusted fees of {scid_B}.*"])


def get_chan_fees(l, scid):
    for half in l.rpc.listchannels(scid)["channels"]:
        if l.info["id"] == half["source"]:
            return (half["base_fee_millisatoshi"], half["fee_per_millionth"])


def wait_for_fees(l, scids, fees):
    for scid in scids:
        wait_for(lambda: get_chan_fees(l, scid) == fees)


def wait_for_not_fees(l, scids, fees):
    for scid in scids:
        wait_for(lambda: not get_chan_fees(l, scid) == fees)


def pay(l, ll, amount):
    label = ''.join(random.choices(string.ascii_letters, k=20))
    invoice = ll.rpc.invoice(amount, label, "desc")
    route = l.rpc.getroute(ll.info["id"], amount, riskfactor=0, fuzzpercent=0)
    l.rpc.sendpay(route["route"], invoice["payment_hash"], payment_secret=invoice.get('payment_secret'))
    l.rpc.waitsendpay(invoice["payment_hash"])


def sync_gossip(nodes, scids):
    node = nodes[0]
    nodes = nodes[1:]
    for scid in scids:
        for n in nodes:
            wait_for(lambda: node.rpc.listchannels(scid) == n.rpc.listchannels(scid))


@unittest.skipIf(not DEVELOPER, "Too slow without fast gossip")
def test_feeadjuster_adjusts(node_factory):
    """
    A rather simple network:

            A                   B
    l1  <========>   l2   <=========>  l3

    l2 will adjust its configuration-set base and proportional fees for
    channels A and B as l1 and l3 exchange payments.
    """
    base_fee = 5000
    ppm_fee = 300
    l2_opts = {
        "fee-base": base_fee,
        "fee-per-satoshi": ppm_fee,
        "plugin": plugin_path,
        "feeadjuster-deactivate-fuzz": None,
    }
    l1, l2, l3 = node_factory.line_graph(3, opts=[{}, l2_opts, {}],
                                         wait_for_announce=True)

    chan_A = l2.rpc.listpeers(l1.info["id"])["peers"][0]["channels"][0]
    chan_B = l2.rpc.listpeers(l3.info["id"])["peers"][0]["channels"][0]
    scid_A = chan_A["short_channel_id"]
    scid_B = chan_B["short_channel_id"]
    nodes = [l1, l2, l3]
    scids = [scid_A, scid_B]

    # Fees don't get updated until there is a forwarding event!
    assert all([get_chan_fees(l2, scid) == (base_fee, ppm_fee)
                for scid in scids])

    chan_total = int(chan_A["total_msat"])
    assert chan_total == int(chan_B["total_msat"])

    # The first payment will trigger fee adjustment, no matter its value
    amount = int(chan_total * 0.04)
    pay(l1, l3, amount)
    wait_for(lambda: all([get_chan_fees(l2, scid) != (base_fee, ppm_fee)
                          for scid in scids]))

    # Send most of the balance to the other side..
    amount = int(chan_total * 0.8)
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([f'Adjusted fees of {scid_A} with a ratio of 0.2',
                             f'Adjusted fees of {scid_B} with a ratio of 3.'])

    # ..And back
    sync_gossip(nodes, scids)
    pay(l3, l1, amount)
    l2.daemon.wait_for_logs([f'Adjusted fees of {scid_A} with a ratio of 6.',
                             f'Adjusted fees of {scid_B} with a ratio of 0.1'])

    # Sending a payment worth 3% of the channel balance should not trigger
    # fee adjustment
    sync_gossip(nodes, scids)
    fees_before = [get_chan_fees(l2, scid) for scid in [scid_A, scid_B]]
    amount = int(chan_total * 0.03)
    pay(l1, l3, amount)
    sync_gossip(nodes, scids)
    assert fees_before == [get_chan_fees(l2, scid) for scid in scids]

    # But sending another 3%-worth payment does trigger adjustment (total sent
    # since last adjustment is >5%)
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([f'Adjusted fees of {scid_A} with a ratio of 4.',
                             f'Adjusted fees of {scid_B} with a ratio of 0.2'])


@unittest.skipIf(not DEVELOPER, "Too slow without fast gossip")
def test_feeadjuster_imbalance(node_factory):
    """
    A rather simple network:

            A                   B
    l1  <========>   l2   <=========>  l3

    l2 will adjust its configuration-set base and proportional fees for
    channels A and B as l1 and l3 exchange payments.
    """
    base_fee = 5000
    ppm_fee = 300
    l2_opts = {
        "fee-base": base_fee,
        "fee-per-satoshi": ppm_fee,
        "plugin": plugin_path,
        "feeadjuster-deactivate-fuzz": None,
        "feeadjuster-imbalance": 0.7,  # should be normalized to 30/70
    }
    l1, l2, l3 = node_factory.line_graph(3, opts=[{}, l2_opts, {}],
                                         wait_for_announce=True)

    chan_A = l2.rpc.listpeers(l1.info["id"])["peers"][0]["channels"][0]
    chan_B = l2.rpc.listpeers(l3.info["id"])["peers"][0]["channels"][0]
    scid_A = chan_A["short_channel_id"]
    scid_B = chan_B["short_channel_id"]
    scids = [scid_A, scid_B]
    default_fees = [(base_fee, ppm_fee), (base_fee, ppm_fee)]

    chan_total = int(chan_A["total_msat"])
    assert chan_total == int(chan_B["total_msat"])
    l2.daemon.wait_for_log('imbalance of 30%/70%')

    # we force feeadjust initially to test this method and check if it applies
    # default fees when balancing the channel below
    l2.rpc.feeadjust()
    l2.daemon.wait_for_logs([
        f"Adjusted fees.*{scid_A}",
        f"Adjusted fees.*{scid_B}"
    ])
    log_offset = len(l2.daemon.logs)
    wait_for_not_fees(l2, scids, default_fees[0])

    # First bring channel to somewhat of a balance
    amount = int(chan_total * 0.5)
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([
        f'Set default fees as imbalance is too low: {scid_A}',
        f'Set default fees as imbalance is too low: {scid_B}'
    ])
    wait_for_fees(l2, scids, default_fees[0])

    # Because of the 70/30 imbalance limiter, a 15% payment must not yet trigger
    # 50% + 15% = 65% .. which is < 70%
    amount = int(chan_total * 0.15)
    pay(l1, l3, amount)
    assert not l2.daemon.is_in_log("Adjusted fees", log_offset)

    # Sending another 20% must now trigger because the imbalance
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([
        f"Adjusted fees.*{scid_A}",
        f"Adjusted fees.*{scid_B}"
    ])
    wait_for_not_fees(l2, scids, default_fees[0])

    # Bringing it back must cause default fees
    pay(l3, l1, amount)
    l2.daemon.wait_for_logs([
        f'Set default fees as imbalance is too low: {scid_A}',
        f'Set default fees as imbalance is too low: {scid_B}'
    ])
    wait_for_fees(l2, scids, default_fees[0])


@unittest.skipIf(not DEVELOPER, "Too slow without fast gossip")
def test_feeadjuster_big_enough_liquidity(node_factory):
    """
    A rather simple network:

            A                   B
    l1  <========>   l2   <=========>  l3

    l2 will adjust its configuration-set base and proportional fees for
    channels A and B as l1 and l3 exchange payments.
    """
    base_fee = 5000
    ppm_fee = 300
    l2_opts = {
        "fee-base": base_fee,
        "fee-per-satoshi": ppm_fee,
        "plugin": plugin_path,
        "feeadjuster-deactivate-fuzz": None,
        "feeadjuster-imbalance": 0.5,
        "feeadjuster-enough-liquidity": "0.001btc",
        "feeadjuster-threshold-abs": "0.0001btc",
    }
    # channels' size: 0.01btc
    # between 0.001btc and 0.009btc the liquidity is big enough
    l1, l2, l3 = node_factory.line_graph(3, fundamount=10**6, opts=[{}, l2_opts, {}],
                                         wait_for_announce=True)

    chan_A = l2.rpc.listpeers(l1.info["id"])["peers"][0]["channels"][0]
    chan_B = l2.rpc.listpeers(l3.info["id"])["peers"][0]["channels"][0]
    scid_A = chan_A["short_channel_id"]
    scid_B = chan_B["short_channel_id"]
    scids = [scid_A, scid_B]
    default_fees = [(base_fee, ppm_fee), (base_fee, ppm_fee)]

    chan_total = int(chan_A["total_msat"])
    assert chan_total == int(chan_B["total_msat"])
    l2.daemon.logsearch_start = 0
    l2.daemon.wait_for_log('enough_liquidity: 100000000msat')

    # we force feeadjust initially to test this method and check if it applies
    # default fees when balancing the channel below
    l2.rpc.feeadjust()
    l2.daemon.wait_for_logs([
        f"Adjusted fees.*{scid_A}",
        f"Adjusted fees.*{scid_B}"
    ])
    wait_for_not_fees(l2, scids, default_fees[0])

    # Bring channels to beyond big enough liquidity with 0.003btc
    amount = 300000000
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([
        f"Adjusted fees of {scid_A} with a ratio of 1.0",
        f"Adjusted fees of {scid_B} with a ratio of 1.0"
    ])
    log_offset = len(l2.daemon.logs)
    wait_for_fees(l2, scids, default_fees[0])

    # Let's move another 0.003btc -> the channels will be at 0.006btc
    amount = 300000000
    pay(l1, l3, amount)
    l2.wait_for_htlcs()
    assert not l2.daemon.is_in_log("Adjusted fees", log_offset)

    # Sending another 0.0033btc will result in a channel balance of 0.0093btc
    # It must trigger because the remaining liquidity is not big enough
    amount = 330000000
    pay(l1, l3, amount)
    l2.daemon.wait_for_logs([
        f"Adjusted fees.*{scid_A}",
        f"Adjusted fees.*{scid_B}"
    ])
    wait_for_not_fees(l2, scids, default_fees[0])

# noqa: F401,F403 # Test dynamically # Then statically # Start at 0 and 're-await' the two inits above. Otherwise this is flaky. # We adjust fees in init A rather simple network:              A                   B     l1  <========>   l2   <=========>  l3      l2 will adjust its configuration-set base and proportional fees for     channels A and B as l1 and l3 exchange payments. # Fees don't get updated until there is a forwarding event! # The first payment will trigger fee adjustment, no matter its value # Send most of the balance to the other side.. # ..And back # Sending a payment worth 3% of the channel balance should not trigger # fee adjustment # But sending another 3%-worth payment does trigger adjustment (total sent # since last adjustment is >5%) A rather simple network:              A                   B     l1  <========>   l2   <=========>  l3      l2 will adjust its configuration-set base and proportional fees for     channels A and B as l1 and l3 exchange payments. # should be normalized to 30/70 # we force feeadjust initially to test this method and check if it applies # default fees when balancing the channel below # First bring channel to somewhat of a balance # Because of the 70/30 imbalance limiter, a 15% payment must not yet trigger # 50% + 15% = 65% .. which is < 70% # Sending another 20% must now trigger because the imbalance # Bringing it back must cause default fees A rather simple network:              A                   B     l1  <========>   l2   <=========>  l3      l2 will adjust its configuration-set base and proportional fees for     channels A and B as l1 and l3 exchange payments. # channels' size: 0.01btc # between 0.001btc and 0.009btc the liquidity is big enough # we force feeadjust initially to test this method and check if it applies # default fees when balancing the channel below # Bring channels to beyond big enough liquidity with 0.003btc # Let's move another 0.003btc -> the channels will be at 0.006btc # Sending another 0.0033btc will result in a channel balance of 0.0093btc # It must trigger because the remaining liquidity is not big enough