Exemplo n.º 1
0
def test_rebalancing_fee_calculation():
    sample = calculate_imbalance_fees(TokenAmount(200),
                                      ProportionalFeeAmount(50_000))  # 5%
    assert sample is not None
    assert len(sample) == NUM_DISCRETISATION_POINTS
    assert all(0 <= x <= 200 for x, _ in sample)
    assert max(x for x, _ in sample) == 200
    assert all(0 <= y <= 10 for _, y in sample)
    assert max(y
               for _, y in sample) == 10  # 5% of the 200 TokenAmount capacity

    sample = calculate_imbalance_fees(TokenAmount(100),
                                      ProportionalFeeAmount(20_000))  # 2%
    assert sample is not None
    assert len(sample) == NUM_DISCRETISATION_POINTS
    assert all(0 <= x <= 100 for x, _ in sample)
    assert max(x for x, _ in sample) == 100
    assert all(0 <= y <= 2 for _, y in sample)
    assert max(y for _, y in sample) == 2  # 2% of the 100 TokenAmount capacity

    sample = calculate_imbalance_fees(TokenAmount(15),
                                      ProportionalFeeAmount(50_000))  # 5%
    assert sample is not None
    assert len(sample) == 16
    assert all(0 <= x <= 16 for x, _ in sample)
    assert max(x for x, _ in sample) == 15
    assert all(0 <= y <= 1 for _, y in sample)
    assert max(y for _, y in sample) == 1  # 5% of the 5 rounded up

    # test rounding of the max_balance_fee calculation
    sample = calculate_imbalance_fees(TokenAmount(1000),
                                      ProportionalFeeAmount(5_490))  # 0.549%
    assert sample is not None
    assert len(sample) == NUM_DISCRETISATION_POINTS
    assert all(0 <= x <= 1000 for x, _ in sample)
    assert max(x for x, _ in sample) == 1000
    assert all(0 <= y <= 5 for _, y in sample)
    assert max(y for _, y in sample) == 5  # 5.49 is rounded to 5

    sample = calculate_imbalance_fees(TokenAmount(1000),
                                      ProportionalFeeAmount(5_500))  # 0.55%
    assert sample is not None
    assert len(sample) == NUM_DISCRETISATION_POINTS
    assert all(0 <= x <= 1000 for x, _ in sample)
    assert max(x for x, _ in sample) == 1000
    assert all(0 <= y <= 6 for _, y in sample)
    assert max(y for _, y in sample) == 6  # 5.5 is rounded to 6

    # test cases where no imbalance fee is created
    assert calculate_imbalance_fees(TokenAmount(0),
                                    ProportionalFeeAmount(1)) is None
    assert calculate_imbalance_fees(TokenAmount(10),
                                    ProportionalFeeAmount(0)) is None
Exemplo n.º 2
0
def test_fee_round_trip(flat_fee, prop_fee, imbalance_fee, amount):
    """ Tests mediation fee deduction. """
    balance = TokenAmount(100_000)
    prop_fee_per_channel = ppm_fee_per_channel(ProportionalFeeAmount(prop_fee))
    imbalance_fee = calculate_imbalance_fees(
        channel_capacity=balance,
        proportional_imbalance_fee=ProportionalFeeAmount(imbalance_fee))
    payer_channel = factories.create(
        NettingChannelStateProperties(
            our_state=NettingChannelEndStateProperties(balance=TokenAmount(0)),
            partner_state=NettingChannelEndStateProperties(balance=balance),
            fee_schedule=FeeScheduleState(
                flat=FeeAmount(flat_fee),
                proportional=prop_fee_per_channel,
                imbalance_penalty=imbalance_fee,
            ),
        ))
    payer_channel_backwards = factories.create(
        NettingChannelStateProperties(
            partner_state=NettingChannelEndStateProperties(
                balance=TokenAmount(0)),
            our_state=NettingChannelEndStateProperties(balance=balance),
            fee_schedule=FeeScheduleState(
                flat=FeeAmount(flat_fee),
                proportional=prop_fee_per_channel,
                imbalance_penalty=imbalance_fee,
            ),
        ))
    payee_channel = factories.create(
        NettingChannelStateProperties(
            our_state=NettingChannelEndStateProperties(balance=balance),
            partner_state=NettingChannelEndStateProperties(
                balance=TokenAmount(0)),
            fee_schedule=FeeScheduleState(
                flat=FeeAmount(flat_fee),
                proportional=prop_fee_per_channel,
                imbalance_penalty=imbalance_fee,
            ),
        ))

    fee_calculation = get_initial_payment_for_final_target_amount(
        final_amount=PaymentAmount(amount),
        channels=[payer_channel_backwards, payee_channel])
    assert fee_calculation

    amount_after_fees = get_lock_amount_after_fees(
        lock=make_hash_time_lock_state(amount=fee_calculation.total_amount),
        payer_channel=payer_channel,
        payee_channel=payee_channel,
    )
    assert amount_after_fees

    assert abs(amount - amount_after_fees) < 100
Exemplo n.º 3
0
def test_fee_add_remove_invariant(flat_fee, prop_fee, imbalance_fee, amount, balance1, balance2):
    """ First adding and then removing fees must yield the original value """
    total_balance = TokenAmount(100_000_000_000_000_000_000)
    prop_fee_per_channel = ppm_fee_per_channel(ProportionalFeeAmount(prop_fee))
    imbalance_fee = calculate_imbalance_fees(
        channel_capacity=total_balance,
        proportional_imbalance_fee=ProportionalFeeAmount(imbalance_fee),
    )
    fee_schedule = FeeScheduleState(
        cap_fees=False,
        flat=FeeAmount(flat_fee),
        proportional=prop_fee_per_channel,
        imbalance_penalty=imbalance_fee,
    )
    channel_in = factories.create(
        NettingChannelStateProperties(
            our_state=NettingChannelEndStateProperties(balance=total_balance - balance1),
            partner_state=NettingChannelEndStateProperties(balance=balance1),
            fee_schedule=fee_schedule,
        )
    )
    channel_out = factories.create(
        NettingChannelStateProperties(
            our_state=NettingChannelEndStateProperties(balance=balance2),
            partner_state=NettingChannelEndStateProperties(balance=total_balance - balance2),
            fee_schedule=fee_schedule,
        )
    )

    amount_with_fees = get_amount_with_fees(
        amount_without_fees=amount,
        schedule_in=channel_in.fee_schedule,
        schedule_out=channel_out.fee_schedule,
        receivable_amount=balance1,
        balance_in=total_balance - balance1,
        balance_out=balance2,
    )
    assume(amount_with_fees)
    assert amount_with_fees
    amount_without_fees = get_amount_without_fees(
        amount_with_fees=amount_with_fees, channel_in=channel_in, channel_out=channel_out
    )
    assume(amount_without_fees)
    assert amount - 1 <= amount_without_fees <= amount + 1
Exemplo n.º 4
0
def test_get_lock_amount_after_fees_imbalanced_channel(
    cap_fees, flat_fee, prop_fee, imbalance_fee, initial_amount, expected_amount
):
    """ Tests mediation fee deduction. """
    balance = TokenAmount(100_000)
    prop_fee_per_channel = ppm_fee_per_channel(ProportionalFeeAmount(prop_fee))
    imbalance_fee = calculate_imbalance_fees(
        channel_capacity=balance, proportional_imbalance_fee=ProportionalFeeAmount(imbalance_fee)
    )
    lock = make_hash_time_lock_state(amount=initial_amount)
    channel_in = factories.create(
        NettingChannelStateProperties(
            our_state=NettingChannelEndStateProperties(balance=TokenAmount(0)),
            partner_state=NettingChannelEndStateProperties(balance=balance),
            fee_schedule=FeeScheduleState(
                cap_fees=cap_fees,
                flat=FeeAmount(flat_fee),
                proportional=prop_fee_per_channel,
                imbalance_penalty=imbalance_fee,
            ),
        )
    )
    channel_out = factories.create(
        NettingChannelStateProperties(
            our_state=NettingChannelEndStateProperties(balance=balance),
            partner_state=NettingChannelEndStateProperties(balance=TokenAmount(0)),
            fee_schedule=FeeScheduleState(
                cap_fees=cap_fees,
                flat=FeeAmount(flat_fee),
                proportional=prop_fee_per_channel,
                imbalance_penalty=imbalance_fee,
            ),
        )
    )

    locked_after_fees = get_amount_without_fees(
        amount_with_fees=lock.amount, channel_in=channel_in, channel_out=channel_out
    )
    assert locked_after_fees == expected_amount
Exemplo n.º 5
0
def test_fee_round_trip(flat_fee, prop_fee, imbalance_fee, amount, balance1, balance2):
    """Tests mediation fee deduction.

    First we're doing a PFS-like calculation going backwards from the target
    amount to get the amount that the initiator has to send. Then we calculate
    the fees from a mediator's point of view and check if `amount_with_fees -
    fees = amount`.
    """
    # Find examples where there is a reasonable chance of succeeding
    amount = int(min(amount, balance1 * 0.95 - 1, balance2 * 0.95 - 1))
    assume(amount > 0)

    total_balance = TokenAmount(100_000_000_000_000_000_000)
    prop_fee_per_channel = ppm_fee_per_channel(ProportionalFeeAmount(prop_fee))
    imbalance_fee = calculate_imbalance_fees(
        channel_capacity=total_balance,
        proportional_imbalance_fee=ProportionalFeeAmount(imbalance_fee),
    )
    channel_in = factories.create(
        NettingChannelStateProperties(
            our_state=NettingChannelEndStateProperties(balance=total_balance - balance1),
            partner_state=NettingChannelEndStateProperties(balance=balance1),
            fee_schedule=FeeScheduleState(
                cap_fees=False,
                flat=FeeAmount(flat_fee),
                proportional=prop_fee_per_channel,
                imbalance_penalty=imbalance_fee,
            ),
        )
    )
    channel_out = factories.create(
        NettingChannelStateProperties(
            our_state=NettingChannelEndStateProperties(balance=balance2),
            partner_state=NettingChannelEndStateProperties(balance=total_balance - balance2),
            fee_schedule=FeeScheduleState(
                cap_fees=False,
                flat=FeeAmount(flat_fee),
                proportional=prop_fee_per_channel,
                imbalance_penalty=imbalance_fee,
            ),
        )
    )

    # How much do we need to send so that the target receives `amount`? PFS-like calculation.
    fee_calculation = get_initial_amount_for_amount_after_fees(
        amount_after_fees=PaymentAmount(amount), channels=[(channel_in, channel_out)]
    )
    assume(fee_calculation)  # There is not enough capacity for the payment in all cases
    assert fee_calculation

    # How much would a mediator send to the target? Ideally exactly `amount`.
    amount_without_margin_after_fees = get_amount_without_fees(
        amount_with_fees=fee_calculation.total_amount,
        channel_in=channel_in,
        channel_out=channel_out,
    )
    assume(amount_without_margin_after_fees)  # We might lack capacity for the payment
    assert abs(amount - amount_without_margin_after_fees) <= 1  # Equal except for rounding errors

    # If we add the fee margin, the mediator must always send at least `amount` to the target!
    amount_with_fee_and_margin = calculate_safe_amount_with_fee(
        fee_calculation.amount_without_fees, FeeAmount(sum(fee_calculation.mediation_fees))
    )
    amount_with_margin_after_fees = get_amount_without_fees(
        amount_with_fees=amount_with_fee_and_margin, channel_in=channel_in, channel_out=channel_out
    )
    assume(amount_with_margin_after_fees)  # We might lack capacity to add margins
    assert amount_with_margin_after_fees >= amount