From fd8f33fd42dbbe11c930bdf1b3a2b3e0861ab1ab Mon Sep 17 00:00:00 2001 From: ffranr Date: Mon, 30 Sep 2024 16:48:58 +0100 Subject: [PATCH] multi: replace SellAccept.BidPrice with AssetRate This commit replaces the SellAccept.BidPrice field with AssetRate, changing a `uint64` price to an asset-to-BTC rate represented as a fixed-point number. --- rfq/negotiator.go | 30 ++++++++------------- rfq/order.go | 5 ++-- rfqmsg/accept.go | 3 ++- rfqmsg/sell_accept.go | 45 +++++++++++++++---------------- rpcserver.go | 5 ++-- tapchannel/aux_invoice_manager.go | 3 ++- tapchannel/aux_traffic_shaper.go | 7 +++-- taprpc/marshal.go | 5 ++-- 8 files changed, 51 insertions(+), 52 deletions(-) diff --git a/rfq/negotiator.go b/rfq/negotiator.go index 252ad1b6c..f8635c3fa 100644 --- a/rfq/negotiator.go +++ b/rfq/negotiator.go @@ -3,12 +3,14 @@ package rfq import ( "fmt" "math" + "math/big" "sync" "time" "github.com/btcsuite/btcd/btcec/v2" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/fn" + "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightninglabs/taproot-assets/rfqmsg" "github.com/lightningnetwork/lnd/lnutils" "github.com/lightningnetwork/lnd/lnwire" @@ -425,16 +427,8 @@ func (n *Negotiator) HandleIncomingSellRequest( } // Construct and send a sell accept message. - // - // TODO(ffranr): This is a temporary solution which will be - // re-written once RFQ quote request messages are updated to - // include a suggested asset rate. - bidPrice := lnwire.MilliSatoshi( - assetRate.Coefficient.ToUint64(), - ) - msg := rfqmsg.NewSellAcceptFromRequest( - request, bidPrice, rateExpiry, + request, *assetRate, rateExpiry, ) sendOutgoingMsg(msg) }() @@ -760,24 +754,22 @@ func (n *Negotiator) HandleIncomingSellAccept(msg rfqmsg.SellAccept, return } - // TODO(ffranr): Temp solution. - oraclePrice := lnwire.MilliSatoshi( - assetRate.Coefficient.ToUint64(), - ) - // Ensure that the peer provided price is reasonable given the // price provided by the price oracle service. - acceptablePrice := pricesWithinBounds( - msg.BidPrice, oraclePrice, - n.cfg.AcceptPriceDeviationPpm, + tolerance := rfqmath.NewBigInt( + big.NewInt(0).SetUint64(n.cfg.AcceptPriceDeviationPpm), + ) + acceptablePrice := msg.AssetRate.WithinTolerance( + *assetRate, tolerance, ) if !acceptablePrice { // The price is not within the acceptable bounds. // We will return without calling the quote accept // callback. log.Debugf("Sell accept quote price is not within "+ - "acceptable bounds (peer_price=%d, "+ - "oracle_price=%d)", msg.BidPrice, oraclePrice) + "acceptable bounds (asset_rate=%v, "+ + "oracle_asset_rate=%v)", msg.AssetRate, + assetRate) // Construct an invalid quote response event so that we // can inform the peer that the quote response has not diff --git a/rfq/order.go b/rfq/order.go index a0e13efc8..ffa6fb47f 100644 --- a/rfq/order.go +++ b/rfq/order.go @@ -233,8 +233,9 @@ func NewAssetPurchasePolicy(quote rfqmsg.SellAccept) *AssetPurchasePolicy { scid: quote.ShortChannelId(), AcceptedQuoteId: quote.ID, AssetAmount: quote.Request.AssetAmount, - BidPrice: quote.BidPrice, - expiry: quote.Expiry, + // TODO(ffranr): Temp solution. + BidPrice: lnwire.MilliSatoshi(quote.AssetRate.ToUint64()), + expiry: quote.Expiry, } } diff --git a/rfqmsg/accept.go b/rfqmsg/accept.go index be46a45bf..4a46f77ee 100644 --- a/rfqmsg/accept.go +++ b/rfqmsg/accept.go @@ -96,7 +96,8 @@ func newAcceptWireMsgDataFromSell(q SellAccept) acceptWireMsgData { // request, we set the out-in rate tick instead of the in-out rate tick. outInRateTick := tlv.SomeRecordT[tlv.TlvType5]( tlv.NewPrimitiveRecord[tlv.TlvType5]( - uint64(q.BidPrice), + // TODO(ffranr): Temp solution. + q.AssetRate.Coefficient.ToUint64(), ), ) diff --git a/rfqmsg/sell_accept.go b/rfqmsg/sell_accept.go index b6204a6c8..aaadc3744 100644 --- a/rfqmsg/sell_accept.go +++ b/rfqmsg/sell_accept.go @@ -3,7 +3,6 @@ package rfqmsg import ( "fmt" - "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/tlv" ) @@ -30,9 +29,8 @@ type SellAccept struct { // message that this response is associated with. ID ID - // BidPrice is the bid price that the message author is willing to pay - // for the asset that is for sale. - BidPrice lnwire.MilliSatoshi + // AssetRate is the accepted asset to BTC rate. + AssetRate BigIntFixedPoint // Expiry is the bid price expiry lifetime unix timestamp. Expiry uint64 @@ -43,16 +41,16 @@ type SellAccept struct { // NewSellAcceptFromRequest creates a new instance of an asset sell quote accept // message given an asset sell quote request message. -func NewSellAcceptFromRequest(request SellRequest, bidPrice lnwire.MilliSatoshi, +func NewSellAcceptFromRequest(request SellRequest, assetRate BigIntFixedPoint, expiry uint64) *SellAccept { return &SellAccept{ - Peer: request.Peer, - Request: request, - Version: latestSellAcceptVersion, - ID: request.ID, - BidPrice: bidPrice, - Expiry: expiry, + Peer: request.Peer, + Request: request, + Version: latestSellAcceptVersion, + ID: request.ID, + AssetRate: assetRate, + Expiry: expiry, } } @@ -72,23 +70,24 @@ func newSellAcceptFromWireMsg(wireMsg WireMessage, // field (and not the in-out rate tick field) because this is the rate // tick field populated in response to a peer initiated sell quote // request. - var bidPrice lnwire.MilliSatoshi + var assetRate BigIntFixedPoint msgData.OutInRateTick.WhenSome( func(rate tlv.RecordT[tlv.TlvType5, uint64]) { - bidPrice = lnwire.MilliSatoshi(rate.Val) + // TODO(ffranr): Temp solution. + assetRate = NewBigIntFixedPoint(rate.Val, 0) }, ) // Note that the `Request` field is populated later in the RFQ stream // service. return &SellAccept{ - Peer: wireMsg.Peer, - Request: request, - Version: msgData.Version.Val, - ID: msgData.ID.Val, - BidPrice: bidPrice, - Expiry: msgData.Expiry.Val, - sig: msgData.Sig.Val, + Peer: wireMsg.Peer, + Request: request, + Version: msgData.Version.Val, + ID: msgData.ID.Val, + AssetRate: assetRate, + Expiry: msgData.Expiry.Val, + sig: msgData.Sig.Val, }, nil } @@ -135,9 +134,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_price=%d, "+ - "expiry=%d, scid=%d)", q.Peer[:], q.ID[:], q.BidPrice, q.Expiry, - q.ShortChannelId()) + 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()) } // Ensure that the message type implements the OutgoingMsg interface. diff --git a/rpcserver.go b/rpcserver.go index 4a6f6d453..1ee59b8ec 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6632,8 +6632,9 @@ func marshalPeerAcceptedSellQuotes( Id: quote.ID[:], Scid: uint64(scid), AssetAmount: quote.Request.AssetAmount, - BidPrice: uint64(quote.BidPrice), - Expiry: quote.Expiry, + // TODO(ffranr): Temp solution. + BidPrice: quote.AssetRate.ToUint64(), + Expiry: quote.Expiry, } rpcQuotes = append(rpcQuotes, rpcQuote) } diff --git a/tapchannel/aux_invoice_manager.go b/tapchannel/aux_invoice_manager.go index 50ad8eaab..f27fdc869 100644 --- a/tapchannel/aux_invoice_manager.go +++ b/tapchannel/aux_invoice_manager.go @@ -222,7 +222,8 @@ func (s *AuxInvoiceManager) priceFromQuote(rfqID rfqmsg.ID) ( log.Debugf("Found sell quote for ID %x / SCID %d: %#v", rfqID[:], rfqID.Scid(), sellQuote) - return sellQuote.BidPrice, nil + // TODO(ffranr): Temp solution. + return lnwire.MilliSatoshi(sellQuote.AssetRate.ToUint64()), nil default: return 0, fmt.Errorf("no accepted quote found for RFQ SCID "+ diff --git a/tapchannel/aux_traffic_shaper.go b/tapchannel/aux_traffic_shaper.go index 47259004f..07bbf852d 100644 --- a/tapchannel/aux_traffic_shaper.go +++ b/tapchannel/aux_traffic_shaper.go @@ -218,7 +218,8 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob, "%x (SCID %d)", rfqID[:], rfqID.Scid()) } - mSatPerAssetUnit := quote.BidPrice + // TODO(ffranr): Temp solution. + mSatPerAssetUnit := lnwire.MilliSatoshi(quote.AssetRate.ToUint64()) // At this point we have acquired what we need to express the asset // bandwidth expressed in satoshis. Before we return the result, we need @@ -285,7 +286,9 @@ func (s *AuxTrafficShaper) ProduceHtlcExtraData(totalAmount lnwire.MilliSatoshi, // nearest 10 units to avoid more than half an asset unit of rounding // error that we would get if we did normal integer division (rounding // down). - mSatPerAssetUnit := quote.BidPrice + // + // TODO(ffranr): Temp solution. + mSatPerAssetUnit := lnwire.MilliSatoshi(quote.AssetRate.ToUint64()) numAssetUnits := uint64(totalAmount*10/mSatPerAssetUnit) / 10 // We now know how many units we need. We take the asset ID from the diff --git a/taprpc/marshal.go b/taprpc/marshal.go index e8954999d..68afc162b 100644 --- a/taprpc/marshal.go +++ b/taprpc/marshal.go @@ -570,8 +570,9 @@ func MarshalAcceptedSellQuoteEvent( Id: event.ID[:], Scid: uint64(event.ShortChannelId()), AssetAmount: event.Request.AssetAmount, - BidPrice: uint64(event.BidPrice), - Expiry: event.Expiry, + // TODO(ffranr): Temp solution. + BidPrice: event.AssetRate.ToUint64(), + Expiry: event.Expiry, } }