From ffa577d2a32320fc92cb5c6ae8e8aa3bbaf5de81 Mon Sep 17 00:00:00 2001 From: ffranr Date: Thu, 26 Sep 2024 16:59:08 +0100 Subject: [PATCH] rfq: replace AssetSalePolicy.AskPrice with asset-to-BTC rate This commit modifies the AssetSalePolicy struct to carry the asset-to-BTC rate instead of a "price". It also updates the policy check equations to use the new rate field. --- rfq/order.go | 42 ++++++++++++++++++++++++++++++------------ rfqmath/convert.go | 4 ++++ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/rfq/order.go b/rfq/order.go index 93f9369503..b67b5ff028 100644 --- a/rfq/order.go +++ b/rfq/order.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "math/big" "sync" "time" @@ -11,6 +12,7 @@ import ( "github.com/lightninglabs/lndclient" "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/input" "github.com/lightningnetwork/lnd/lnutils" @@ -87,9 +89,8 @@ type AssetSalePolicy struct { // requested. MaxAssetAmount uint64 - // AskPrice is the asking price of the quote in milli-satoshis per asset - // unit. - AskPrice lnwire.MilliSatoshi + // AskAssetRate is the quote's asking asset unit to BTC conversion rate. + AskAssetRate rfqmsg.Uint64FixedPoint // expiry is the policy's expiry unix timestamp after which the policy // is no longer valid. @@ -104,12 +105,9 @@ func NewAssetSalePolicy(quote rfqmsg.BuyAccept) *AssetSalePolicy { return &AssetSalePolicy{ ID: quote.ID, MaxAssetAmount: quote.Request.AssetAmount, - // TODO(ffranr): Temp solution. - AskPrice: lnwire.MilliSatoshi( - quote.AssetRate.Coefficient.ToUint64(), - ), - expiry: quote.Expiry, - assetID: quote.Request.AssetID, + AskAssetRate: quote.AssetRate, + expiry: quote.Expiry, + assetID: quote.Request.AssetID, } } @@ -128,7 +126,16 @@ func (c *AssetSalePolicy) CheckHtlcCompliance( // Check that the HTLC amount is not greater than the negotiated maximum // amount. - maxOutboundAmount := lnwire.MilliSatoshi(c.MaxAssetAmount) * c.AskPrice + askAssetRate := c.AskAssetRate.ToBigIntFixedPoint() + + maxAssetAmount := rfqmsg.NewBigIntFixedPoint( + new(big.Int).SetUint64(c.MaxAssetAmount), 0, + ) + + maxOutboundAmount := rfqmath.UnitsToMilliSatoshi( + maxAssetAmount, askAssetRate, + ) + if htlc.AmountOutMsat > maxOutboundAmount { return fmt.Errorf("htlc out amount is greater than the policy "+ "maximum (htlc_out_msat=%d, policy_max_out_msat=%d)", @@ -175,8 +182,19 @@ func (c *AssetSalePolicy) GenerateInterceptorResponse( return nil, fmt.Errorf("policy has no asset ID") } - outgoingAssetAmount := uint64(htlc.AmountOutMsat / c.AskPrice) - htlcBalance := rfqmsg.NewAssetBalance(*c.assetID, outgoingAssetAmount) + // Compute the outgoing asset amount given the msat outgoing amount and + // the asset to BTC rate. + askAssetRate := rfqmath.FixedPoint[rfqmath.GoInt[uint64]]{ + Coefficient: c.AskAssetRate.Coefficient, + Scale: c.AskAssetRate.Scale, + } + outgoingAssetAmount := rfqmath.MilliSatoshiToUnits( + htlc.AmountOutMsat, askAssetRate, + ) + amt := outgoingAssetAmount.ScaleTo(0).ToUint64() + + // Include the asset balance in the HTLC record. + htlcBalance := rfqmsg.NewAssetBalance(*c.assetID, amt) htlcRecord := rfqmsg.NewHtlc( []*rfqmsg.AssetBalance{htlcBalance}, fn.Some(c.ID), ) diff --git a/rfqmath/convert.go b/rfqmath/convert.go index 21d753d591..c1c246d169 100644 --- a/rfqmath/convert.go +++ b/rfqmath/convert.go @@ -62,6 +62,10 @@ func MilliSatoshiToUnits[N Int[N]](milliSat lnwire.MilliSatoshi, // compute the total amount of mSAT (X) as follows: // - X = (U / Y) * M // - where M is the number of mSAT in a BTC (100,000,000,000). +// +// TODO(ffranr): This function only works with BigInt as the underlying +// integer type. For built-in integer types, oneBtcInMilliSat overflows. +// We should remove the type generic or reformulate. func UnitsToMilliSatoshi[N Int[N]](assetUnits, unitsPerBtc FixedPoint[N]) lnwire.MilliSatoshi {