diff --git a/itest/channels_test.go b/itest/channels_test.go index 9a3a91c23..6021592d7 100644 --- a/itest/channels_test.go +++ b/itest/channels_test.go @@ -3,6 +3,8 @@ package itest import ( "context" + "github.com/lightninglabs/taproot-assets/internal/test" + "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightninglabs/taproot-assets/rfqmsg" tchrpc "github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc" "github.com/lightningnetwork/lnd/lnrpc" @@ -66,6 +68,26 @@ func testChannelRPCs(t *harnessTest) { "payment", ) + // Make sure that the minimum satoshi amount for a keysend payment is + // enforced. + stream, err = t.tapd.SendPayment(ctx, &tchrpc.SendPaymentRequest{ + AssetAmount: 123, + AssetId: dummyByteArr[:], + PaymentRequest: &routerrpc.SendPaymentRequest{ + Dest: test.RandPubKey(t.t).SerializeCompressed(), + DestCustomRecords: map[uint64][]byte{ + record.KeySendType: dummyByteArr[:], + }, + Amt: int64(rfqmath.DefaultOnChainHtlcSat - 1), + }, + }) + require.NoError(t.t, err) + + _, err = stream.Recv() + require.ErrorContains( + t.t, err, "keysend payment satoshi amount must be greater", + ) + // Now let's also try the invoice path, which should fail because we // don't have any asset channels with peers that we could ask for a // quote. diff --git a/rpcserver.go b/rpcserver.go index ef069f3f6..1ae629bc4 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -7798,6 +7798,16 @@ func (r *rpcServer) SendPayment(req *tchrpc.SendPaymentRequest, "pubkey: %w", err) } + // We must enforce a minimum satoshi amount to make sure the + // carrier HTLC is above dust. This is handled by the traffic + // shaper for invoice-based payments, but for keysend payments + // we need to do it here. + if pReq.Amt < int64(rfqmath.DefaultOnChainHtlcSat) { + return fmt.Errorf("keysend payment satoshi amount "+ + "must be greater than or equal to %d satoshis", + rfqmath.DefaultOnChainHtlcSat) + } + // We check that we have the asset amount available in the // channel. _, err = r.cfg.RfqManager.FetchChannel(