diff --git a/rfq/manager.go b/rfq/manager.go index bd1cb7e28..7bc589cd1 100644 --- a/rfq/manager.go +++ b/rfq/manager.go @@ -826,7 +826,7 @@ func (m *Manager) PeerAcceptedSellQuotes() SellAcceptMap { sellQuotesCopy := make(map[SerialisedScid]rfqmsg.SellAccept) m.peerAcceptedSellQuotes.ForEach( func(scid SerialisedScid, accept rfqmsg.SellAccept) error { - if time.Now().Unix() > int64(accept.Expiry) { + if time.Now().After(accept.AssetRate.Expiry) { m.peerAcceptedSellQuotes.Delete(scid) return nil } @@ -870,7 +870,7 @@ func (m *Manager) LocalAcceptedSellQuotes() SellAcceptMap { sellQuotesCopy := make(map[SerialisedScid]rfqmsg.SellAccept) m.localAcceptedSellQuotes.ForEach( func(scid SerialisedScid, accept rfqmsg.SellAccept) error { - if time.Now().Unix() > int64(accept.Expiry) { + if time.Now().After(accept.AssetRate.Expiry) { m.localAcceptedSellQuotes.Delete(scid) return nil } diff --git a/rfq/negotiator.go b/rfq/negotiator.go index a9d37199e..2dae0721f 100644 --- a/rfq/negotiator.go +++ b/rfq/negotiator.go @@ -446,10 +446,7 @@ func (n *Negotiator) HandleIncomingSellRequest( } // Construct and send a sell accept message. - expiry := uint64(assetRate.Expiry.Unix()) - msg := rfqmsg.NewSellAcceptFromRequest( - request, assetRate.Rate, expiry, - ) + msg := rfqmsg.NewSellAcceptFromRequest(request, *assetRate) sendOutgoingMsg(msg) }() @@ -679,10 +676,12 @@ func (n *Negotiator) HandleIncomingSellAccept(msg rfqmsg.SellAccept, // // TODO(ffranr): Sanity check the quote expiry timestamp given // the expiry timestamp provided by the price oracle. - if !expiryWithinBounds(msg.Expiry, minAssetRatesExpiryLifetime) { + expiry := uint64(msg.AssetRate.Expiry.Unix()) + if !expiryWithinBounds(expiry, minAssetRatesExpiryLifetime) { // The expiry time is not within the acceptable bounds. log.Debugf("Sell accept quote expiry time is not within "+ - "acceptable bounds (expiry=%d)", msg.Expiry) + "acceptable bounds (asset_rate=%s)", + msg.AssetRate.String()) // Construct an invalid quote response event so that we can // inform the peer that the quote response has not validated @@ -762,7 +761,7 @@ func (n *Negotiator) HandleIncomingSellAccept(msg rfqmsg.SellAccept, tolerance := rfqmath.NewBigIntFromUint64( n.cfg.AcceptPriceDeviationPpm, ) - acceptablePrice := msg.AssetRate.WithinTolerance( + acceptablePrice := msg.AssetRate.Rate.WithinTolerance( assetRate.Rate, tolerance, ) if !acceptablePrice { diff --git a/rfq/order.go b/rfq/order.go index 150c9aa61..b41c2889d 100644 --- a/rfq/order.go +++ b/rfq/order.go @@ -262,9 +262,9 @@ func NewAssetPurchasePolicy(quote rfqmsg.SellAccept) *AssetPurchasePolicy { scid: quote.ShortChannelId(), AssetSpecifier: quote.Request.AssetSpecifier, AcceptedQuoteId: quote.ID, - BidAssetRate: quote.AssetRate, + BidAssetRate: quote.AssetRate.Rate, PaymentMaxAmt: quote.Request.PaymentMaxAmt, - expiry: quote.Expiry, + expiry: uint64(quote.AssetRate.Expiry.Unix()), } } diff --git a/rfqmsg/accept.go b/rfqmsg/accept.go index b17c31798..c4e6ca86b 100644 --- a/rfqmsg/accept.go +++ b/rfqmsg/accept.go @@ -76,7 +76,10 @@ func newAcceptWireMsgDataFromBuy(q BuyAccept) (acceptWireMsgData, error) { func newAcceptWireMsgDataFromSell(q SellAccept) (acceptWireMsgData, error) { version := tlv.NewPrimitiveRecord[tlv.TlvType0](q.Version) id := tlv.NewRecordT[tlv.TlvType2](q.ID) - expiry := tlv.NewPrimitiveRecord[tlv.TlvType4](q.Expiry) + + expiryUnix := q.AssetRate.Expiry.Unix() + expiry := tlv.NewPrimitiveRecord[tlv.TlvType4](uint64(expiryUnix)) + sig := tlv.NewPrimitiveRecord[tlv.TlvType6](q.sig) // Currently, only BTC is supported as the incoming asset in sell @@ -87,7 +90,7 @@ func newAcceptWireMsgDataFromSell(q SellAccept) (acceptWireMsgData, error) { // The rate provided in the sell acceptance message represents the // exchange rate from the outgoing asset to BTC. - rate := NewTlvFixedPointFromBigInt(q.AssetRate) + rate := NewTlvFixedPointFromBigInt(q.AssetRate.Rate) outAssetRate := tlv.NewRecordT[tlv.TlvType10](rate) // Encode message data component as TLV bytes. diff --git a/rfqmsg/sell_accept.go b/rfqmsg/sell_accept.go index 81c3439fa..1e1701d97 100644 --- a/rfqmsg/sell_accept.go +++ b/rfqmsg/sell_accept.go @@ -2,8 +2,8 @@ package rfqmsg import ( "fmt" + "time" - "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightningnetwork/lnd/routing/route" ) @@ -30,10 +30,7 @@ type SellAccept struct { ID ID // AssetRate is the accepted asset to BTC rate. - AssetRate rfqmath.BigIntFixedPoint - - // Expiry is the bid price expiry lifetime unix timestamp. - Expiry uint64 + AssetRate AssetRate // sig is a signature over the serialized contents of the message. sig [64]byte @@ -41,10 +38,8 @@ type SellAccept struct { // NewSellAcceptFromRequest creates a new instance of an asset sell quote accept // message given an asset sell quote request message. -// -// // TODO(ffranr): Use new AssetRate type for assetRate arg. func NewSellAcceptFromRequest(request SellRequest, - assetRate rfqmath.BigIntFixedPoint, expiry uint64) *SellAccept { + assetRate AssetRate) *SellAccept { return &SellAccept{ Peer: request.Peer, @@ -52,7 +47,6 @@ func NewSellAcceptFromRequest(request SellRequest, Version: latestSellAcceptVersion, ID: request.ID, AssetRate: assetRate, - Expiry: expiry, } } @@ -72,6 +66,9 @@ func newSellAcceptFromWireMsg(wireMsg WireMessage, // currently assume that the in-asset is BTC. assetRate := msgData.OutAssetRate.Val.IntoBigIntFixedPoint() + // Convert the unix timestamp in seconds to a time.Time. + expiry := time.Unix(int64(msgData.Expiry.Val), 0).UTC() + // Note that the `Request` field is populated later in the RFQ stream // service. return &SellAccept{ @@ -79,8 +76,7 @@ func newSellAcceptFromWireMsg(wireMsg WireMessage, Request: request, Version: msgData.Version.Val, ID: msgData.ID.Val, - AssetRate: assetRate, - Expiry: msgData.Expiry.Val, + AssetRate: NewAssetRate(assetRate, expiry), sig: msgData.Sig.Val, }, nil } @@ -133,9 +129,9 @@ func (q *SellAccept) MsgID() ID { // String returns a human-readable string representation of the message. func (q *SellAccept) String() string { - return fmt.Sprintf("SellAccept(peer=%x, id=%x, bid_asset_rate=%v, "+ - "expiry=%d, scid=%d)", q.Peer[:], q.ID[:], q.AssetRate, - q.Expiry, q.ShortChannelId()) + return fmt.Sprintf("SellAccept(peer=%x, id=%x, asset_rate=%s, "+ + "scid=%d)", q.Peer[:], q.ID[:], q.AssetRate.String(), + q.ShortChannelId()) } // Ensure that the message type implements the OutgoingMsg interface. diff --git a/rpcserver.go b/rpcserver.go index 544d47e24..a7eef5f5d 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6628,8 +6628,8 @@ func marshalPeerAcceptedSellQuotes(quotes map[rfq.SerialisedScid]rfqmsg.SellAcce rpcQuotes := make([]*rfqrpc.PeerAcceptedSellQuote, 0, len(quotes)) for scid, quote := range quotes { rpcAssetRate := &rfqrpc.FixedPoint{ - Coefficient: quote.AssetRate.Coefficient.String(), - Scale: uint32(quote.AssetRate.Scale), + Coefficient: quote.AssetRate.Rate.Coefficient.String(), + Scale: uint32(quote.AssetRate.Rate.Scale), } // TODO(ffranr): Add SellRequest payment max amount to @@ -6639,7 +6639,7 @@ func marshalPeerAcceptedSellQuotes(quotes map[rfq.SerialisedScid]rfqmsg.SellAcce Id: quote.ID[:], Scid: uint64(scid), BidAssetRate: rpcAssetRate, - Expiry: quote.Expiry, + Expiry: uint64(quote.AssetRate.Expiry.Unix()), } rpcQuotes = append(rpcQuotes, rpcQuote) } diff --git a/tapchannel/aux_invoice_manager.go b/tapchannel/aux_invoice_manager.go index f0630b620..7fcad8c9a 100644 --- a/tapchannel/aux_invoice_manager.go +++ b/tapchannel/aux_invoice_manager.go @@ -273,7 +273,7 @@ func (s *AuxInvoiceManager) priceFromQuote(rfqID rfqmsg.ID) ( log.Debugf("Found sell quote for ID %x / SCID %d: %#v", rfqID[:], rfqID.Scid(), sellQuote) - return &sellQuote.AssetRate, nil + return &sellQuote.AssetRate.Rate, nil default: return nil, fmt.Errorf("no accepted quote found for RFQ SCID "+ diff --git a/tapchannel/aux_traffic_shaper.go b/tapchannel/aux_traffic_shaper.go index f017a9a7e..1974f58ed 100644 --- a/tapchannel/aux_traffic_shaper.go +++ b/tapchannel/aux_traffic_shaper.go @@ -224,7 +224,7 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob, // expressed in milli-satoshis. localBalanceFp := rfqmath.NewBigIntFixedPoint(localBalance, 0) availableBalanceMsat := rfqmath.UnitsToMilliSatoshi( - localBalanceFp, quote.AssetRate, + localBalanceFp, quote.AssetRate.Rate, ) // At this point we have acquired what we need to express the asset @@ -283,7 +283,7 @@ func (s *AuxTrafficShaper) ProduceHtlcExtraData(totalAmount lnwire.MilliSatoshi, // corresponding number of assets, then reduce the number of satoshis of // the HTLC to the bare minimum that can be materialized on chain. numAssetUnitsFp := rfqmath.MilliSatoshiToUnits( - totalAmount, quote.AssetRate, + totalAmount, quote.AssetRate.Rate, ) numAssetUnits := numAssetUnitsFp.ScaleTo(0).ToUint64() diff --git a/taprpc/marshal.go b/taprpc/marshal.go index d2a2ac3f7..8ad92df6d 100644 --- a/taprpc/marshal.go +++ b/taprpc/marshal.go @@ -567,8 +567,8 @@ func MarshalAcceptedSellQuoteEvent( error) { rpcAssetRate := &rfqrpc.FixedPoint{ - Coefficient: event.AssetRate.Coefficient.String(), - Scale: uint32(event.AssetRate.Scale), + Coefficient: event.AssetRate.Rate.Coefficient.String(), + Scale: uint32(event.AssetRate.Rate.Scale), } // TODO(ffranr): Add SellRequest payment max amount to @@ -578,7 +578,7 @@ func MarshalAcceptedSellQuoteEvent( Id: event.ID[:], Scid: uint64(event.ShortChannelId()), BidAssetRate: rpcAssetRate, - Expiry: event.Expiry, + Expiry: uint64(event.AssetRate.Expiry.Unix()), }, nil }