From 4cc020380cf6146827feff3512a286363d0fec37 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sun, 15 Dec 2024 17:07:15 +0100 Subject: [PATCH] rpc: for DecodeAssetPayReq hit the oracle directly We just want to map the amount in BTC to asset units. So we rely on our local oracle. Otherwise if we hit the peer directly, then it's more similar to `EstimateRouteFee`. --- config.go | 2 ++ rpcserver.go | 68 +++++++++++++++++++++++++++--------------------- tapcfg/server.go | 1 + 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/config.go b/config.go index 189046374..b4e9d800e 100644 --- a/config.go +++ b/config.go @@ -195,6 +195,8 @@ type Config struct { RfqManager *rfq.Manager + PriceOracle rfq.PriceOracle + UniverseStats universe.Telemetry AuxLeafSigner *tapchannel.AuxLeafSigner diff --git a/rpcserver.go b/rpcserver.go index fa511f2f9..58c5ed945 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -7732,18 +7732,29 @@ func (r *rpcServer) getInboundPolicy(ctx context.Context, chanID uint64, // assetInvoiceAmt calculates the amount of asset units to pay for an invoice // which is expressed in sats. -func (r *rpcServer) assetInvoiceAmt(ctx context.Context, assetID asset.ID, - invoiceAmt lnwire.MilliSatoshi, peerPubKey *route.Vertex, - expiryTimestamp time.Time) (uint64, error) { +func (r *rpcServer) assetInvoiceAmt(ctx context.Context, targetAsset asset.Specifier, + invoiceAmt lnwire.MilliSatoshi) (uint64, error) { + + oracle := r.cfg.PriceOracle - acceptedQuote, err := r.fetchSendRfqQuote( - ctx, assetID, invoiceAmt, peerPubKey, expiryTimestamp, + oracleResp, err := oracle.QueryAskPrice( + ctx, targetAsset, fn.None[uint64](), fn.Some(invoiceAmt), + fn.None[rfqmsg.AssetRate](), ) if err != nil { - return 0, fmt.Errorf("error sending RFQ quote: %w", err) + return 0, fmt.Errorf("error querying ask price: %w", err) + } + if oracleResp.Err != nil { + return 0, fmt.Errorf("error querying ask price: %w", err) } - return acceptedQuote.AssetAmount, nil + assetRate := oracleResp.AssetRate.Rate + + numAssetUnits := rfqmath.MilliSatoshiToUnits( + invoiceAmt, assetRate, + ).ScaleTo(0) + + return numAssetUnits.ToUint64(), nil } // DecodeAssetPayReq decodes an incoming invoice, then uses the RFQ system to @@ -7751,6 +7762,10 @@ func (r *rpcServer) assetInvoiceAmt(ctx context.Context, assetID asset.ID, func (r *rpcServer) DecodeAssetPayReq(ctx context.Context, payReq *tchrpc.AssetPayReqString) (*tchrpc.AssetPayReq, error) { + if r.cfg.PriceOracle == nil { + return nil, fmt.Errorf("price oracle is not set") + } + // First, we'll perform some basic input validation. switch { case len(payReq.AssetId) == 0: @@ -7783,28 +7798,6 @@ func (r *rpcServer) DecodeAssetPayReq(ctx context.Context, resp.PayReq = payReqInfo - // TODO(roasbeef): add dry run mode? - // * obtains quote, but doesn't actually treat as standing order - - // Now that we have the basic invoice information, we'll query the RFQ - // system to obtain a quote to send this amount of BTC. Note that this - // doesn't factor in the fee limit, so this attempts just to map the - // sats amount to an asset unit. - timestamp := time.Unix(payReqInfo.Timestamp, 0) - expiryTimestamp := timestamp.Add(time.Duration(payReqInfo.Expiry)) - numMsat := lnwire.NewMSatFromSatoshis( - btcutil.Amount(payReqInfo.NumSatoshis), - ) - invoiceAmt, err := r.assetInvoiceAmt( - ctx, assetID, numMsat, nil, - expiryTimestamp, - ) - if err != nil { - return nil, fmt.Errorf("error deriving asset amount: %w", err) - } - - resp.AssetAmount = invoiceAmt - // Next, we'll fetch the information for this asset ID through the addr // book. This'll automatically fetch the asset if needed. assetGroup, err := r.cfg.AddrBook.QueryAssetInfo(ctx, assetID) @@ -7841,6 +7834,23 @@ func (r *rpcServer) DecodeAssetPayReq(ctx context.Context, } } + // Now that we have the basic invoice information, we'll query the RFQ + // system to obtain a quote to send this amount of BTC. Note that this + // doesn't factor in the fee limit, so this attempts just to map the + // sats amount to an asset unit. + numMsat := lnwire.NewMSatFromSatoshis( + btcutil.Amount(payReqInfo.NumSatoshis), + ) + targetAsset := asset.NewSpecifierOptionalGroupKey( + assetGroup.ID(), assetGroup.GroupKey, + ) + invoiceAmt, err := r.assetInvoiceAmt(ctx, targetAsset, numMsat) + if err != nil { + return nil, fmt.Errorf("error deriving asset amount: %w", err) + } + + resp.AssetAmount = invoiceAmt + // The final piece of information we need is the decimal display // information for this asset ID. decDisplay, err := r.DecDisplayForAssetID(ctx, assetID) diff --git a/tapcfg/server.go b/tapcfg/server.go index c3204177f..131075a66 100644 --- a/tapcfg/server.go +++ b/tapcfg/server.go @@ -582,6 +582,7 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger, UniverseQueriesPerSecond: cfg.Universe.UniverseQueriesPerSecond, UniverseQueriesBurst: cfg.Universe.UniverseQueriesBurst, RfqManager: rfqManager, + PriceOracle: priceOracle, AuxLeafSigner: auxLeafSigner, AuxFundingController: auxFundingController, AuxChanCloser: auxChanCloser,