liquidity: generalize threshold rule variable names

The current wording in this function is very specific to loop out.
In this commit, we refactor to use `target` and `reserve` rather
than inbound and outbound so that it can be used more generically.
pull/433/head
carla 2 years ago
parent 06c4c347fd
commit 00c2d4e5f0
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91

@ -65,73 +65,99 @@ func (r *ThresholdRule) validate() error {
// swapAmount suggests a swap based on the liquidity thresholds configured, // swapAmount suggests a swap based on the liquidity thresholds configured,
// returning zero if no swap is recommended. // returning zero if no swap is recommended.
func (r *ThresholdRule) swapAmount(channel *balances, func (r *ThresholdRule) swapAmount(channel *balances,
outRestrictions *Restrictions) btcutil.Amount { restrictions *Restrictions) btcutil.Amount {
var (
// For loop out swaps, we want to adjust our incoming liquidity
// so the channel's incoming balance is our target.
targetBalance = channel.incoming
// For loop out swaps, we target a minimum amount of incoming
// liquidity, so the minimum incoming threshold is our target
// percentage.
targetPercentage = uint64(r.MinimumIncoming)
// For loop out swaps, we may want to preserve some of our
// outgoing balance, so the channel's outgoing balance is our
// reserve.
reserveBalance = channel.outgoing
// For loop out swaps, we may want to preserve some percentage
// of our outgoing balance, so the minimum outgoing threshold
// is our reserve percentage.
reservePercentage = uint64(r.MinimumOutgoing)
)
// Examine our total balance and required ratios to decide whether we // Examine our total balance and required ratios to decide whether we
// need to swap. // need to swap.
amount := loopOutSwapAmount( amount := calculateSwapAmount(
channel, r.MinimumIncoming, r.MinimumOutgoing, targetBalance, reserveBalance, channel.capacity,
targetPercentage, reservePercentage,
) )
// Limit our swap amount by the minimum/maximum thresholds set. // Limit our swap amount by the minimum/maximum thresholds set.
switch { switch {
case amount < outRestrictions.Minimum: case amount < restrictions.Minimum:
return 0 return 0
case amount > outRestrictions.Maximum: case amount > restrictions.Maximum:
return outRestrictions.Maximum return restrictions.Maximum
default: default:
return amount return amount
} }
} }
// loopOutSwapAmount determines whether we can perform a loop out swap, and // calculateSwapAmount calculates amount for a swap based on thresholds.
// returns the amount we need to swap to reach the desired liquidity balance // This function can be used for loop out or loop in, but the concept is the
// specified by the incoming and outgoing thresholds. // same - we want liquidity in one (target) direction, while preserving some
func loopOutSwapAmount(balances *balances, incomingThresholdPercent, // minimum in the other (reserve) direction.
outgoingThresholdPercent int) btcutil.Amount { // * target: this is the side of the channel(s) where we want to acquire some
// liquidity. We aim for this liquidity to reach the threshold amount set.
minimumIncoming := btcutil.Amount(uint64( // * reserve: this is the side of the channel(s) that we will move liquidity
balances.capacity) * // away from. This may not drop below a certain reserve threshold.
uint64(incomingThresholdPercent) / 100, func calculateSwapAmount(targetAmount, reserveAmount,
capacity btcutil.Amount, targetThresholdPercentage,
reserveThresholdPercentage uint64) btcutil.Amount {
targetGoal := btcutil.Amount(
uint64(capacity) * targetThresholdPercentage / 100,
) )
minimumOutgoing := btcutil.Amount( reserveMinimum := btcutil.Amount(
uint64(balances.capacity) * uint64(capacity) * reserveThresholdPercentage / 100,
uint64(outgoingThresholdPercent) / 100,
) )
switch { switch {
// If we have sufficient incoming capacity, we do not need to loop out. // If we have sufficient target capacity, we do not need to swap.
case balances.incoming >= minimumIncoming: case targetAmount >= targetGoal:
return 0 return 0
// If we are already below the threshold set for outgoing capacity, we // If we are already below the threshold set for reserve capacity, we
// cannot take any further action. // cannot take any further action.
case balances.outgoing <= minimumOutgoing: case reserveAmount <= reserveMinimum:
return 0 return 0
} }
// Express our minimum outgoing amount as a maximum incoming amount. // Express our minimum reserve amount as a maximum target amount.
// We will use this value to limit the amount that we swap, so that we // We will use this value to limit the amount that we swap, so that we
// do not dip below our outgoing threshold. // do not dip below our reserve threshold.
maximumIncoming := balances.capacity - minimumOutgoing maximumTarget := capacity - reserveMinimum
// Calculate the midpoint between our minimum and maximum incoming // Calculate the midpoint between our minimum and maximum target values.
// values. We will aim to swap this amount so that we do not tip our // We will aim to swap this amount so that we do not tip our reserve
// outgoing balance beneath the desired level. // balance beneath the desired level.
midpoint := (minimumIncoming + maximumIncoming) / 2 midpoint := (targetGoal + maximumTarget) / 2
// Calculate the amount of incoming balance we need to shift to reach // Calculate the amount of target balance we need to shift to reach
// this desired midpoint. // this desired midpoint.
required := midpoint - balances.incoming required := midpoint - targetAmount
// Since we can have pending htlcs on our channel, we check the amount // Since we can have pending htlcs on our channel, we check the amount
// of outbound capacity that we can shift before we fall below our // of reserve capacity that we can shift before we fall below our
// threshold. // threshold.
available := balances.outgoing - minimumOutgoing available := reserveAmount - reserveMinimum
// If we do not have enough balance available to reach our midpoint, we // If we do not have enough balance available to reach our midpoint, we
// take no action. This is the case when we have a large portion of // take no action. This is the case when we have a large portion of

@ -93,18 +93,18 @@ func TestValidateThreshold(t *testing.T) {
} }
} }
// TestLoopOutAmount tests assessing of a set of balances to determine whether // TestCalculateAmount tests calculation of the amount we recommend for a given
// we should perform a loop out. // set of balances and threshold rule.
func TestLoopOutAmount(t *testing.T) { func TestCalculateAmount(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
minIncoming int minIncoming uint64
minOutgoing int minOutgoing uint64
balances *balances balances *balances
amt btcutil.Amount amt btcutil.Amount
}{ }{
{ {
name: "insufficient surplus", name: "insufficient outgoing",
balances: &balances{ balances: &balances{
capacity: 100, capacity: 100,
incoming: 20, incoming: 20,
@ -166,8 +166,9 @@ func TestLoopOutAmount(t *testing.T) {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
t.Parallel() t.Parallel()
amt := loopOutSwapAmount( amt := calculateSwapAmount(
test.balances, test.minIncoming, test.balances.incoming, test.balances.outgoing,
test.balances.capacity, test.minIncoming,
test.minOutgoing, test.minOutgoing,
) )
require.Equal(t, test.amt, amt) require.Equal(t, test.amt, amt)

Loading…
Cancel
Save