Skip to content

Commit 7c7df7d

Browse files
committed
fixup
1 parent af8256f commit 7c7df7d

File tree

10 files changed

+956
-735
lines changed

10 files changed

+956
-735
lines changed

assets/client.go

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
package assets
22

33
import (
4+
"context"
5+
"fmt"
6+
"math/big"
47
"os"
8+
"time"
59

10+
"github.com/btcsuite/btcd/btcutil"
11+
"github.com/lightninglabs/taproot-assets/rfqmath"
612
"github.com/lightninglabs/taproot-assets/taprpc"
13+
"github.com/lightninglabs/taproot-assets/taprpc/priceoraclerpc"
14+
"github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
715
"github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc"
816
"github.com/lightningnetwork/lnd/macaroons"
917
"google.golang.org/grpc"
@@ -33,6 +41,15 @@ func DefaultTapdConfig() *TapdConfig {
3341
}
3442
}
3543

44+
// TapdClient is a client for the Tap daemon.
45+
type TapdClient struct {
46+
cc *grpc.ClientConn
47+
taprpc.TaprootAssetsClient
48+
tapchannelrpc.TaprootAssetChannelsClient
49+
priceoraclerpc.PriceOracleClient
50+
rfqrpc.RfqClient
51+
}
52+
3653
// NewTapdClient retusn a new taproot assets client.
3754
func NewTapdClient(config *TapdConfig) (*TapdClient, error) {
3855
// Create the client connection to the server.
@@ -46,6 +63,8 @@ func NewTapdClient(config *TapdConfig) (*TapdClient, error) {
4663
cc: conn,
4764
TaprootAssetsClient: taprpc.NewTaprootAssetsClient(conn),
4865
TaprootAssetChannelsClient: tapchannelrpc.NewTaprootAssetChannelsClient(conn),
66+
PriceOracleClient: priceoraclerpc.NewPriceOracleClient(conn),
67+
RfqClient: rfqrpc.NewRfqClient(conn),
4968
}
5069

5170
return client, nil
@@ -56,11 +75,57 @@ func (c *TapdClient) Close() {
5675
c.cc.Close()
5776
}
5877

59-
// TapdClient is a client for the Tap daemon.
60-
type TapdClient struct {
61-
cc *grpc.ClientConn
62-
taprpc.TaprootAssetsClient
63-
tapchannelrpc.TaprootAssetChannelsClient
78+
func (c *TapdClient) GetSatAmountForAsset(ctx context.Context,
79+
amt btcutil.Amount, assetId, peerPubkey []byte) (btcutil.Amount,
80+
error) {
81+
82+
rfq, err := c.RfqClient.AddAssetSellOrder(
83+
ctx, &rfqrpc.AddAssetSellOrderRequest{
84+
AssetSpecifier: &rfqrpc.AssetSpecifier{
85+
Id: &rfqrpc.AssetSpecifier_AssetId{ // nolint:lll
86+
AssetId: assetId,
87+
},
88+
},
89+
PeerPubKey: peerPubkey,
90+
PaymentMaxAmt: uint64(amt),
91+
Expiry: uint64(time.Now().Add(1 * time.Hour).Unix()),
92+
TimeoutSeconds: 60,
93+
})
94+
if err != nil {
95+
return 0, err
96+
}
97+
if rfq.GetInvalidQuote() != nil {
98+
return 0, fmt.Errorf("invalid RFQ: %v", rfq.GetInvalidQuote())
99+
}
100+
if rfq.GetRejectedQuote() != nil {
101+
return 0, fmt.Errorf("rejected RFQ: %v", rfq.GetRejectedQuote())
102+
}
103+
104+
if rfq.GetAcceptedQuote() != nil {
105+
payRate := rfq.GetAcceptedQuote().BidAssetRate
106+
107+
coefficient := new(big.Int)
108+
coefficient, ok := coefficient.SetString(payRate.Coefficient, 10)
109+
if !ok {
110+
return 0, fmt.Errorf("failed to parse coefficient %v",
111+
payRate.Coefficient)
112+
}
113+
114+
amt := rfqmath.FixedPointFromUint64[rfqmath.BigInt](
115+
uint64(amt), 0,
116+
)
117+
118+
price := rfqmath.FixedPoint[rfqmath.BigInt]{
119+
Coefficient: rfqmath.NewBigInt(coefficient),
120+
Scale: uint8(payRate.Scale),
121+
}
122+
123+
msats := rfqmath.UnitsToMilliSatoshi(amt, price)
124+
125+
return msats.ToSatoshis(), nil
126+
}
127+
128+
return 0, fmt.Errorf("no accepted quote")
64129
}
65130

66131
func getClientConn(config *TapdConfig) (*grpc.ClientConn, error) {

client.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,18 @@ func (s *Client) resumeSwaps(ctx context.Context,
506506
func (s *Client) LoopOut(globalCtx context.Context,
507507
request *OutRequest) (*LoopOutSwapInfo, error) {
508508

509+
if request.AssetId != nil {
510+
satAmt, err := s.assetClient.GetSatAmountForAsset(
511+
globalCtx, request.AssetAmount, request.AssetId,
512+
request.AssetEdgeNode,
513+
)
514+
if err != nil {
515+
return nil, err
516+
}
517+
518+
request.Amount = satAmt
519+
}
520+
509521
log.Infof("LoopOut %v to %v (channels: %v)",
510522
request.Amount, request.DestAddr, request.OutgoingChanSet,
511523
)
@@ -586,11 +598,24 @@ func (s *Client) LoopOutQuote(ctx context.Context,
586598
return nil, err
587599
}
588600

589-
if request.Amount < terms.MinSwapAmount {
601+
satAmount := request.Amount
602+
// If we use an Asset we'll rfq to check if the sat amount meets the
603+
// min swap amount criteria.
604+
if request.AssetId != nil {
605+
satAmount, err = s.assetClient.GetSatAmountForAsset(
606+
ctx, btcutil.Amount(request.Amount), request.AssetId,
607+
request.PeerPubkey,
608+
)
609+
if err != nil {
610+
return nil, err
611+
}
612+
}
613+
614+
if satAmount < terms.MinSwapAmount {
590615
return nil, ErrSwapAmountTooLow
591616
}
592617

593-
if request.Amount > terms.MaxSwapAmount {
618+
if satAmount > terms.MaxSwapAmount {
594619
return nil, ErrSwapAmountTooHigh
595620
}
596621

@@ -601,7 +626,7 @@ func (s *Client) LoopOutQuote(ctx context.Context,
601626
}
602627

603628
quote, err := s.Server.GetLoopOutQuote(
604-
ctx, request.Amount, expiry, request.SwapPublicationDeadline,
629+
ctx, satAmount, expiry, request.SwapPublicationDeadline,
605630
request.Initiator,
606631
)
607632
if err != nil {
@@ -620,6 +645,7 @@ func (s *Client) LoopOutQuote(ctx context.Context,
620645
MinerFee: minerFee,
621646
PrepayAmount: quote.PrepayAmount,
622647
SwapPaymentDest: quote.SwapPaymentDest,
648+
InvoiceAmtSat: satAmount,
623649
}, nil
624650
}
625651

cmd/loop/loopout.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ func loopOut(ctx *cli.Context) error {
205205
if err != nil {
206206
return err
207207
}
208+
if !ctx.IsSet("asset_edge_node") {
209+
return fmt.Errorf("asset edge node is required when " +
210+
"assetid is set")
211+
}
208212
}
209213

210214
var assetEdgeNode []byte
@@ -239,6 +243,8 @@ func loopOut(ctx *cli.Context) error {
239243
Amt: int64(amt),
240244
ConfTarget: sweepConfTarget,
241245
SwapPublicationDeadline: uint64(swapDeadline.Unix()),
246+
AssetId: assetId,
247+
AssetEdgeNode: assetEdgeNode,
242248
}
243249
quote, err := client.LoopOutQuote(context.Background(), quoteReq)
244250
if err != nil {

cmd/loop/quote.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,15 @@ func printQuoteOutResp(req *looprpc.QuoteRequest,
267267

268268
totalFee := resp.HtlcSweepFeeSat + resp.SwapFeeSat
269269

270-
fmt.Printf(satAmtFmt, "Send off-chain:", req.Amt)
271-
fmt.Printf(satAmtFmt, "Receive on-chain:", req.Amt-totalFee)
270+
if req.AssetId != nil {
271+
fmt.Printf("%-36s %12d assets\n",
272+
"Assets Send off-chain:", req.Amt)
273+
fmt.Printf(satAmtFmt, "Sats Send off-chain:",
274+
resp.InvoiceAmtSat)
275+
} else {
276+
fmt.Printf(satAmtFmt, "Send off-chain:", resp.InvoiceAmtSat)
277+
}
278+
fmt.Printf(satAmtFmt, "Receive on-chain:", resp.InvoiceAmtSat-totalFee)
272279

273280
if !verbose {
274281
fmt.Printf(satAmtFmt, "Estimated total fee:", totalFee)

interface.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ type OutRequest struct {
108108
// tapd server have multiple channels with different peers for the given
109109
// asset id.
110110
AssetEdgeNode []byte
111+
112+
// AssetAmount is the amount of the asset that will be used to pay for
113+
// the swap. This is only set if the asset id is set.
114+
AssetAmount btcutil.Amount
111115
}
112116

113117
// Out contains the full details of a loop out request. This includes things
@@ -155,6 +159,12 @@ type LoopOutQuoteRequest struct {
155159
// initiated the swap (loop CLI, autolooper, LiT UI and so on) and is
156160
// appended to the user agent string.
157161
Initiator string
162+
163+
// AssetId is the asset that we'll quote for.
164+
AssetId []byte
165+
166+
// PeerPubkey is the pubkey of the peer that we'll quote for.
167+
PeerPubkey []byte
158168
}
159169

160170
// LoopOutTerms are the server terms on which it executes swaps.
@@ -191,6 +201,9 @@ type LoopOutQuote struct {
191201
// SwapPaymentDest is the node pubkey where to swap payment needs to be
192202
// sent to.
193203
SwapPaymentDest [33]byte
204+
205+
// InvoiceAmtSat is the amount of the invoice in satoshis.
206+
InvoiceAmtSat btcutil.Amount
194207
}
195208

196209
// LoopInRequest contains the required parameters for the swap.

loopd/swapclient_server.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,18 @@ func (s *swapClientServer) LoopOut(ctx context.Context,
206206
Label: in.Label,
207207
Initiator: in.Initiator,
208208
PaymentTimeout: paymentTimeout,
209-
AssetId: in.AssetId,
210-
AssetEdgeNode: in.AssetEdgeNode,
209+
}
210+
211+
// If the asset id is set, we need to set the asset amount and asset id
212+
// in the request.
213+
if in.AssetId != nil {
214+
req.AssetAmount = btcutil.Amount(in.Amt)
215+
req.AssetId = in.AssetId
216+
req.AssetEdgeNode = in.AssetEdgeNode
217+
218+
// We'll set the sat amount to zero, as this gets set later
219+
// when we calculate the total amount to send.
220+
req.Amount = 0
211221
}
212222

213223
switch {
@@ -714,6 +724,8 @@ func (s *swapClientServer) LoopOutQuote(ctx context.Context,
714724
SweepConfTarget: confTarget,
715725
SwapPublicationDeadline: publicactionDeadline,
716726
Initiator: defaultLoopdInitiator,
727+
AssetId: req.AssetId,
728+
PeerPubkey: req.AssetEdgeNode,
717729
})
718730
if err != nil {
719731
return nil, err
@@ -725,6 +737,7 @@ func (s *swapClientServer) LoopOutQuote(ctx context.Context,
725737
SwapFeeSat: int64(quote.SwapFee),
726738
SwapPaymentDest: quote.SwapPaymentDest[:],
727739
ConfTarget: confTarget,
740+
InvoiceAmtSat: int64(quote.InvoiceAmtSat),
728741
}, nil
729742
}
730743

loopout.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ func (s *loopOutSwap) payInvoices(ctx context.Context) {
655655
s.prePaymentChan = s.payInvoice(
656656
ctx, s.PrepayInvoice, s.MaxPrepayRoutingFee,
657657
s.LoopOutContract.OutgoingChanSet,
658-
s.LoopOutContract.PaymentTimeout, RoutingPluginNone, false, false,
658+
s.LoopOutContract.PaymentTimeout, RoutingPluginNone, false, true,
659659
)
660660
}
661661

@@ -762,9 +762,13 @@ func (s *loopOutSwap) payInvoiceWithAssetClient(ctx context.Context,
762762
continue
763763
}
764764

765-
return &lndclient.PaymentStatus{
766-
State: payRes.Status,
767-
}, nil
765+
if payRes.Status == lnrpc.Payment_SUCCEEDED ||
766+
payRes.Status == lnrpc.Payment_FAILED {
767+
768+
return &lndclient.PaymentStatus{
769+
State: payRes.Status,
770+
}, nil
771+
}
768772
}
769773
}
770774
}

0 commit comments

Comments
 (0)