Skip to content

Commit e7a9d31

Browse files
committed
liquidity: add asset loop out unit test
1 parent b42dcf4 commit e7a9d31

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

liquidity/autoloop_test.go

+145
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package liquidity
22

33
import (
4+
"context"
5+
"encoding/hex"
6+
"encoding/json"
47
"testing"
58
"time"
69

@@ -11,6 +14,7 @@ import (
1114
"github.com/lightninglabs/loop/loopdb"
1215
"github.com/lightninglabs/loop/swap"
1316
"github.com/lightninglabs/loop/test"
17+
"github.com/lightninglabs/taproot-assets/rfqmsg"
1418
"github.com/lightningnetwork/lnd/lntypes"
1519
"github.com/lightningnetwork/lnd/lnwire"
1620
"github.com/lightningnetwork/lnd/routing/route"
@@ -1520,3 +1524,144 @@ func existingInFromRequest(in *loop.LoopInRequest, initTime time.Time,
15201524
},
15211525
}
15221526
}
1527+
1528+
// TestEasyAssetAutoloop tests that the easy asset autoloop logic works as
1529+
//
1530+
// expected. This involves testing that channels are correctly selected and
1531+
//
1532+
// that the balance target is successfully met.
1533+
func TestEasyAssetAutoloop(t *testing.T) {
1534+
defer test.Guard(t)
1535+
1536+
assetId := [32]byte{0x01}
1537+
assetStr := hex.EncodeToString(assetId[:])
1538+
1539+
// Decode a dummy p2wkh address to use as the destination address for
1540+
// the swaps.
1541+
p2wkhAddr := "bcrt1qq68r6ff4k4pjx39efs44gcyccf7unqnu5qtjjz"
1542+
addr, err := btcutil.DecodeAddress(p2wkhAddr, nil)
1543+
require.NoError(t, err)
1544+
1545+
customChanData1 := rfqmsg.JsonAssetChannel{
1546+
Assets: []rfqmsg.JsonAssetChanInfo{
1547+
{
1548+
AssetInfo: rfqmsg.JsonAssetUtxo{
1549+
AssetGenesis: rfqmsg.JsonAssetGenesis{
1550+
AssetID: assetStr,
1551+
},
1552+
},
1553+
LocalBalance: 950000,
1554+
RemoteBalance: 0,
1555+
Capacity: 100000,
1556+
},
1557+
},
1558+
}
1559+
customChanData1Bytes, err := json.Marshal(customChanData1)
1560+
require.NoError(t, err)
1561+
1562+
// We need to change the default channels we use for tests so that they
1563+
// have different local balances in order to know which one is going to
1564+
// be selected by easy autoloop.
1565+
assetChan := lndclient.ChannelInfo{
1566+
Active: true,
1567+
ChannelID: chanID1.ToUint64(),
1568+
PubKeyBytes: peer1,
1569+
LocalBalance: 95000,
1570+
RemoteBalance: 0,
1571+
Capacity: 100000,
1572+
CustomChannelData: customChanData1Bytes,
1573+
}
1574+
1575+
// As the asset price func we'll just return a 1:1 conversion of asset units
1576+
// to satoshis.
1577+
assetPriceFunc := func(ctx context.Context, assetId string,
1578+
peerPubkey []byte, assetAmt uint64, minSatAmt btcutil.Amount) (
1579+
btcutil.Amount, error) {
1580+
1581+
return btcutil.Amount(assetAmt), nil
1582+
}
1583+
1584+
var (
1585+
channels = []lndclient.ChannelInfo{assetChan}
1586+
1587+
params = Parameters{
1588+
Autoloop: true,
1589+
DestAddr: addr,
1590+
AutoFeeBudget: 36000,
1591+
AutoFeeRefreshPeriod: time.Hour * 3,
1592+
AutoloopBudgetLastRefresh: testBudgetStart,
1593+
MaxAutoInFlight: 2,
1594+
FailureBackOff: time.Hour,
1595+
SweepConfTarget: 10,
1596+
HtlcConfTarget: defaultHtlcConfTarget,
1597+
FeeLimit: defaultFeePortion(),
1598+
AssetAutoloopParams: map[string]AssetParams{
1599+
assetStr: AssetParams{
1600+
EnableEasyOut: true,
1601+
LocalTargetAssetAmount: 75000,
1602+
},
1603+
},
1604+
}
1605+
)
1606+
1607+
c := newAutoloopTestCtx(t, params, channels, testRestrictions)
1608+
// Return a fixed price for the asset.
1609+
c.manager.cfg.GetAssetPrice = assetPriceFunc
1610+
1611+
c.start()
1612+
1613+
var (
1614+
maxAmt = 50000
1615+
1616+
chan1Swap = &loop.OutRequest{
1617+
Amount: btcutil.Amount(maxAmt),
1618+
DestAddr: addr,
1619+
OutgoingChanSet: loopdb.ChannelSet{assetChan.ChannelID},
1620+
Label: labels.AutoloopLabel(swap.TypeOut),
1621+
Initiator: autoloopSwapInitiator,
1622+
}
1623+
1624+
quotesOut1 = []quoteRequestResp{
1625+
{
1626+
request: &loop.LoopOutQuoteRequest{
1627+
Amount: btcutil.Amount(maxAmt),
1628+
AssetRFQRequest: &loop.AssetRFQRequest{
1629+
AssetId: assetId[:],
1630+
AssetEdgeNode: []byte("edge"),
1631+
},
1632+
},
1633+
quote: &loop.LoopOutQuote{
1634+
SwapFee: 1,
1635+
PrepayAmount: 1,
1636+
MinerFee: 1,
1637+
// We'll add a fake rfq info to use in the actual swap.
1638+
LoopOutRfq: &loop.LoopOutRfq{
1639+
PrepayRfqId: []byte("prepay"),
1640+
SwapRfqId: []byte("swap"),
1641+
},
1642+
},
1643+
},
1644+
}
1645+
1646+
loopOut1 = []loopOutRequestResp{
1647+
{
1648+
request: chan1Swap,
1649+
response: &loop.LoopOutSwapInfo{
1650+
SwapHash: lntypes.Hash{1},
1651+
},
1652+
},
1653+
}
1654+
)
1655+
1656+
// We expected one max size swap to be dispatched on our channel with
1657+
// the biggest local balance.
1658+
step := &easyAutoloopStep{
1659+
minAmt: 1,
1660+
maxAmt: 50000,
1661+
quotesOut: quotesOut1,
1662+
expectedOut: loopOut1,
1663+
}
1664+
1665+
c.easyautoloop(step, false)
1666+
c.stop()
1667+
}

0 commit comments

Comments
 (0)