diff --git a/.gitignore b/.gitignore index 114e77ec6..0fc14d0d3 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ cmd/tapd/tapd /itest/itest.test /docs/examples/basic-price-oracle/basic-price-oracle +/docs/examples/basic-price-oracle/basic-price-oracle-example.log # Load test binaries and config /loadtest diff --git a/docs/examples/basic-price-oracle/main.go b/docs/examples/basic-price-oracle/main.go index 83609fc7c..28c635879 100644 --- a/docs/examples/basic-price-oracle/main.go +++ b/docs/examples/basic-price-oracle/main.go @@ -306,6 +306,7 @@ func (p *RpcPriceOracleServer) QueryAssetRates(_ context.Context, Error: &oraclerpc.QueryAssetRatesErrResponse{ Message: "unsupported payment asset, " + "only BTC is supported", + Code: 1, }, }, }, nil @@ -326,6 +327,7 @@ func (p *RpcPriceOracleServer) QueryAssetRates(_ context.Context, Result: &oraclerpc.QueryAssetRatesResponse_Error{ Error: &oraclerpc.QueryAssetRatesErrResponse{ Message: "unsupported subject asset", + Code: 1, }, }, }, nil diff --git a/docs/release-notes/release-notes-0.7.0.md b/docs/release-notes/release-notes-0.7.0.md index 17578b0ed..b92d424fb 100644 --- a/docs/release-notes/release-notes-0.7.0.md +++ b/docs/release-notes/release-notes-0.7.0.md @@ -26,8 +26,8 @@ - [An integration test flake was fixed](https://github.com/lightninglabs/taproot-assets/pull/1651). -- Fixed two send related bugs that would lead to either a `invalid transfer - asset witness` or `unable to fund address send: error funding packet: unable +- Fixed two send related bugs that would lead to either a `invalid transfer + asset witness` or `unable to fund address send: error funding packet: unable to list eligible coins: unable to query commitments: mismatch of managed utxo and constructed tap commitment root` error when sending assets. The [PR that fixed the two @@ -119,17 +119,25 @@ when requesting quotes. The field can contain optional user or authentication information that helps the price oracle to decide on the optimal price rate to return. + +- The error code returned in a response from a price oracle now has a + [structured + form](https://github.com/lightninglabs/taproot-assets/pull/1766), + allowing price oracles to either indicate that a given asset is + unsupported, or simply to return an opaque error. "Unsupported asset" + errors are forwarded in reject messages sent to peers. + - [Rename](https://github.com/lightninglabs/taproot-assets/pull/1682) the `MintAsset` RPC message field from `universe_commitments` to `enable_supply_commitments`. -- The `SubscribeSendEvents` RPC now supports [historical event replay of +- The `SubscribeSendEvents` RPC now supports [historical event replay of completed sends with efficient database-level filtering](https://github.com/lightninglabs/taproot-assets/pull/1685). - [Add universe RPC endpoint FetchSupplyLeaves](https://github.com/lightninglabs/taproot-assets/pull/1693) that allows users to fetch the supply leaves of a universe supply commitment. This is useful for verification. -- A [new field `unconfirmed_transfers` was added to the response of the +- A [new field `unconfirmed_transfers` was added to the response of the `ListBalances` RPC method](https://github.com/lightninglabs/taproot-assets/pull/1691) to indicate that unconfirmed asset-related transactions don't count toward the balance. @@ -236,5 +244,6 @@ - ffranr - George Tsagkarelis +- jtobin - Olaoluwa Osuntokun - Oliver Gugger diff --git a/rfq/negotiator.go b/rfq/negotiator.go index b7606129c..f3a2b9947 100644 --- a/rfq/negotiator.go +++ b/rfq/negotiator.go @@ -1,6 +1,7 @@ package rfq import ( + "errors" "fmt" "sync" "time" @@ -27,6 +28,29 @@ const ( DefaultAcceptPriceDeviationPpm = 50_000 ) +// QueryError represents an error with additional context about the price +// oracle query that led to it. +type QueryError struct { + // Err is the error returned from a query attempt, possibly from a + // price oracle. + Err error + + // Context is the context of the price oracle query that led to the + // error. + Context string +} + +// Error returns a human-readable version of the QueryError, implementing the +// main error interface. +func (err *QueryError) Error() string { + // If there's no context, just fall back to the wrapped error. + if err.Context == "" { + return err.Err.Error() + } + // Otherwise prepend the context. + return err.Context + ": " + err.Err.Error() +} + // NegotiatorCfg holds the configuration for the negotiator. type NegotiatorCfg struct { // PriceOracle is the price oracle that the negotiator will use to @@ -141,22 +165,29 @@ func (n *Negotiator) queryBuyFromPriceOracle(assetSpecifier asset.Specifier, counterparty, metadata, intent, ) if err != nil { - return nil, fmt.Errorf("failed to query price oracle for "+ - "buy price: %w", err) + return nil, &QueryError{ + Err: err, + Context: "failed to query price oracle for buy price", + } } // Now we will check for an error in the response from the price oracle. - // If present, we will convert it to a string and return it as an error. + // If present, we will relay it with context. if oracleResponse.Err != nil { - return nil, fmt.Errorf("failed to query price oracle for "+ - "buy price: %s", oracleResponse.Err) + return nil, &QueryError{ + Err: oracleResponse.Err, + Context: "failed to query price oracle for buy price", + } } // By this point, the price oracle did not return an error or a buy // price. We will therefore return an error. if oracleResponse.AssetRate.Rate.ToUint64() == 0 { - return nil, fmt.Errorf("price oracle did not specify a " + - "buy price") + return nil, &QueryError{ + Err: errors.New("price oracle didn't specify " + + "a price"), + Context: "failed to query price oracle for buy price", + } } // TODO(ffranr): Check that the buy price is reasonable. @@ -277,22 +308,29 @@ func (n *Negotiator) querySellFromPriceOracle(assetSpecifier asset.Specifier, counterparty, metadata, intent, ) if err != nil { - return nil, fmt.Errorf("failed to query price oracle for "+ - "sell price: %w", err) + return nil, &QueryError{ + Err: err, + Context: "failed to query price oracle for sell price", + } } // Now we will check for an error in the response from the price oracle. - // If present, we will convert it to a string and return it as an error. + // If present, we will relay it with context. if oracleResponse.Err != nil { - return nil, fmt.Errorf("failed to query price oracle for "+ - "sell price: %s", oracleResponse.Err) + return nil, &QueryError{ + Err: oracleResponse.Err, + Context: "failed to query price oracle for sell price", + } } // By this point, the price oracle did not return an error or a sell // price. We will therefore return an error. if oracleResponse.AssetRate.Rate.Coefficient.ToUint64() == 0 { - return nil, fmt.Errorf("price oracle did not specify an " + - "asset to BTC rate") + return nil, &QueryError{ + Err: errors.New("price oracle didn't specify " + + "a price"), + Context: "failed to query price oracle for sell price", + } } // TODO(ffranr): Check that the sell price is reasonable. @@ -372,10 +410,12 @@ func (n *Negotiator) HandleIncomingBuyRequest( peerID, request.PriceOracleMetadata, IntentRecvPayment, ) if err != nil { - // Send a reject message to the peer. + // Construct an appropriate RejectErr based on + // the oracle's response, and send it to the + // peer. msg := rfqmsg.NewReject( request.Peer, request.ID, - rfqmsg.ErrUnknownReject, + createCustomRejectErr(err), ) sendOutgoingMsg(msg) @@ -473,10 +513,12 @@ func (n *Negotiator) HandleIncomingSellRequest( peerID, request.PriceOracleMetadata, IntentPayInvoice, ) if err != nil { - // Send a reject message to the peer. + // Construct an appropriate RejectErr based on + // the oracle's response, and send it to the + // peer. msg := rfqmsg.NewReject( request.Peer, request.ID, - rfqmsg.ErrUnknownReject, + createCustomRejectErr(err), ) sendOutgoingMsg(msg) @@ -495,6 +537,35 @@ func (n *Negotiator) HandleIncomingSellRequest( return nil } +// createCustomRejectErr creates a RejectErr with code 0 and a custom message +// based on an error response from a price oracle. +func createCustomRejectErr(err error) rfqmsg.RejectErr { + var queryError *QueryError + // Check if the error we've received is the expected QueryError, and + // return an opaque rejection error if not. + if !errors.As(err, &queryError) { + return rfqmsg.ErrUnknownReject + } + + var oracleError *OracleError + // Check if the QueryError contains the expected OracleError, and + // return an opaque rejection error if not. + if !errors.As(queryError, &oracleError) { + return rfqmsg.ErrUnknownReject + } + + switch oracleError.Code { + // The price oracle has indicated that it doesn't support the asset, + // so return a rejection error indicating that. + case UnsupportedAssetOracleErrorCode: + return rfqmsg.ErrRejectWithCustomMsg(oracleError.Msg) + // The error code is either unspecified or unknown, so return an + // opaque rejection error. + default: + return rfqmsg.ErrUnknownReject + } +} + // HandleOutgoingSellOrder handles an outgoing sell order by constructing sell // requests and passing them to the outgoing messages channel. These requests // are sent to peers. diff --git a/rfq/oracle.go b/rfq/oracle.go index e7ee28694..503577bda 100644 --- a/rfq/oracle.go +++ b/rfq/oracle.go @@ -86,12 +86,26 @@ const ( // service. type OracleError struct { // Code is a code which uniquely identifies the error type. - Code uint8 + Code OracleErrorCode // Msg is a human-readable error message. Msg string } +// OracleErrorCode uniquely identifies the kinds of error an oracle may +// return. +type OracleErrorCode uint8 + +const ( + // UnspecifiedOracleErrorCode represents the case where the oracle has + // declined to give a more specific reason for the error. + UnspecifiedOracleErrorCode OracleErrorCode = iota + + // UnsupportedAssetOracleErrorCode represents the case in which an + // oracle does not provide quotes for the requested asset. + UnsupportedAssetOracleErrorCode +) + // Error returns a human-readable string representation of the error. func (o *OracleError) Error() string { // Sanitise price oracle error message by truncating to 255 characters. @@ -356,7 +370,8 @@ func (r *RpcPriceOracle) QuerySellPrice(ctx context.Context, return &OracleResponse{ Err: &OracleError{ - Msg: result.Error.Message, + Msg: result.Error.Message, + Code: marshallErrorCode(result.Error.Code), }, }, nil @@ -365,6 +380,19 @@ func (r *RpcPriceOracle) QuerySellPrice(ctx context.Context, } } +// marshallErrorCode marshalls an over-the-wire error code into an +// OracleErrorCode. +func marshallErrorCode(code oraclerpc.ErrorCode) OracleErrorCode { + switch code { + case oraclerpc.ErrorCode_UNSPECIFIED_ORACLE_ERROR_CODE: + return UnspecifiedOracleErrorCode + case oraclerpc.ErrorCode_UNSUPPORTED_ASSET_ORACLE_ERROR_CODE: + return UnsupportedAssetOracleErrorCode + default: + return UnspecifiedOracleErrorCode + } +} + // QueryBuyPrice returns a buy price for the given asset amount. func (r *RpcPriceOracle) QueryBuyPrice(ctx context.Context, assetSpecifier asset.Specifier, assetMaxAmt fn.Option[uint64], @@ -467,7 +495,8 @@ func (r *RpcPriceOracle) QueryBuyPrice(ctx context.Context, return &OracleResponse{ Err: &OracleError{ - Msg: result.Error.Message, + Msg: result.Error.Message, + Code: marshallErrorCode(result.Error.Code), }, }, nil diff --git a/rfqmsg/reject.go b/rfqmsg/reject.go index 44eef2a6a..821a0798d 100644 --- a/rfqmsg/reject.go +++ b/rfqmsg/reject.go @@ -76,22 +76,42 @@ func (v *RejectErr) Record() tlv.Record { ) } +const ( + // UnspecifiedRejectCode indicates that a request-for-quote was + // rejected, without necessarily providing any further detail as to + // why. + UnspecifiedRejectCode uint8 = iota + + // UnavailableRejectCode indicates that a request-for-quote was + // rejected as a price oracle was unavailable. + UnavailableRejectCode +) + var ( // ErrUnknownReject is the error code for when the quote is rejected // for an unspecified reason. ErrUnknownReject = RejectErr{ - Code: 0, + Code: UnspecifiedRejectCode, Msg: "unknown reject error", } - // ErrPriceOracleUnavailable is the error code for when the price oracle - // is unavailable. + // ErrPriceOracleUnavailable is the error code for when the price + // oracle is unavailable. ErrPriceOracleUnavailable = RejectErr{ - Code: 1, + Code: UnavailableRejectCode, Msg: "price oracle unavailable", } ) +// ErrRejectWithCustomMsg produces the "unknown" error code, but pairs +// it with a custom error message. +func ErrRejectWithCustomMsg(msg string) RejectErr { + return RejectErr{ + Code: UnspecifiedRejectCode, + Msg: msg, + } +} + const ( // latestRejectVersion is the latest supported reject wire message data // field version. diff --git a/taprpc/priceoraclerpc/price_oracle.pb.go b/taprpc/priceoraclerpc/price_oracle.pb.go index c0c0c6026..d26fd91e6 100644 --- a/taprpc/priceoraclerpc/price_oracle.pb.go +++ b/taprpc/priceoraclerpc/price_oracle.pb.go @@ -172,6 +172,57 @@ func (Intent) EnumDescriptor() ([]byte, []int) { return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{1} } +// ErrorCode represents the possible error codes that can be returned in a +// QueryAssetRatesErrResponse. +type ErrorCode int32 + +const ( + // UNSPECIFIED_ORACLE_ERROR_CODE indicates an unspecified error. + ErrorCode_UNSPECIFIED_ORACLE_ERROR_CODE ErrorCode = 0 + // UNSUPPORTED_ASSET_ORACLE_ERROR_CODE indicates the asset is not + // supported. + ErrorCode_UNSUPPORTED_ASSET_ORACLE_ERROR_CODE ErrorCode = 1 +) + +// Enum value maps for ErrorCode. +var ( + ErrorCode_name = map[int32]string{ + 0: "UNSPECIFIED_ORACLE_ERROR_CODE", + 1: "UNSUPPORTED_ASSET_ORACLE_ERROR_CODE", + } + ErrorCode_value = map[string]int32{ + "UNSPECIFIED_ORACLE_ERROR_CODE": 0, + "UNSUPPORTED_ASSET_ORACLE_ERROR_CODE": 1, + } +) + +func (x ErrorCode) Enum() *ErrorCode { + p := new(ErrorCode) + *p = x + return p +} + +func (x ErrorCode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ErrorCode) Descriptor() protoreflect.EnumDescriptor { + return file_priceoraclerpc_price_oracle_proto_enumTypes[2].Descriptor() +} + +func (ErrorCode) Type() protoreflect.EnumType { + return &file_priceoraclerpc_price_oracle_proto_enumTypes[2] +} + +func (x ErrorCode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ErrorCode.Descriptor instead. +func (ErrorCode) EnumDescriptor() ([]byte, []int) { + return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{2} +} + // FixedPoint is a scaled integer representation of a fractional number. // // This type consists of two integer fields: a coefficient and a scale. @@ -657,7 +708,7 @@ type QueryAssetRatesErrResponse struct { // error is the error message. Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` // code is the error code. - Code uint32 `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"` + Code ErrorCode `protobuf:"varint,2,opt,name=code,proto3,enum=priceoraclerpc.ErrorCode" json:"code,omitempty"` } func (x *QueryAssetRatesErrResponse) Reset() { @@ -699,11 +750,11 @@ func (x *QueryAssetRatesErrResponse) GetMessage() string { return "" } -func (x *QueryAssetRatesErrResponse) GetCode() uint32 { +func (x *QueryAssetRatesErrResponse) GetCode() ErrorCode { if x != nil { return x.Code } - return 0 + return ErrorCode_UNSPECIFIED_ORACLE_ERROR_CODE } // QueryAssetRatesResponse is the response from a QueryAssetRates RPC call. @@ -862,50 +913,57 @@ var file_priceoraclerpc_price_oracle_proto_rawDesc = []byte{ 0x0b, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x52, 0x0a, - 0x61, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x22, 0x4a, 0x0a, 0x1a, 0x51, 0x75, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x22, 0x65, 0x0a, 0x1a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x45, 0x72, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0xa4, 0x01, 0x0a, 0x17, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, - 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x4f, - 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x02, 0x6f, 0x6b, 0x12, - 0x42, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, - 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x45, - 0x72, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2a, 0x29, 0x0a, - 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x55, 0x52, 0x43, 0x48, 0x41, 0x53, 0x45, 0x10, 0x00, 0x12, 0x08, - 0x0a, 0x04, 0x53, 0x41, 0x4c, 0x45, 0x10, 0x01, 0x2a, 0xcd, 0x01, 0x0a, 0x06, 0x49, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x12, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x49, + 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x19, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, + 0x63, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, + 0x65, 0x22, 0xa4, 0x01, 0x0a, 0x17, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, + 0x52, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, + 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x4f, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x02, 0x6f, 0x6b, 0x12, 0x42, 0x0a, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x69, 0x63, + 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x45, 0x72, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x08, + 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2a, 0x29, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x50, + 0x55, 0x52, 0x43, 0x48, 0x41, 0x53, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x41, 0x4c, + 0x45, 0x10, 0x01, 0x2a, 0xcd, 0x01, 0x0a, 0x06, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x16, + 0x0a, 0x12, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x54, + 0x5f, 0x50, 0x41, 0x59, 0x5f, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x48, 0x49, 0x4e, + 0x54, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x41, + 0x59, 0x5f, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x41, 0x59, 0x5f, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, - 0x45, 0x5f, 0x48, 0x49, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x49, 0x4e, 0x54, 0x45, - 0x4e, 0x54, 0x5f, 0x50, 0x41, 0x59, 0x5f, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x10, 0x02, - 0x12, 0x1e, 0x0a, 0x1a, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x41, 0x59, 0x5f, 0x49, - 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x51, 0x55, 0x41, 0x4c, 0x49, 0x46, 0x59, 0x10, 0x03, - 0x12, 0x1c, 0x0a, 0x18, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x43, 0x56, 0x5f, - 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x48, 0x49, 0x4e, 0x54, 0x10, 0x04, 0x12, 0x17, - 0x0a, 0x13, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x43, 0x56, 0x5f, 0x50, 0x41, - 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x05, 0x12, 0x1f, 0x0a, 0x1b, 0x49, 0x4e, 0x54, 0x45, 0x4e, - 0x54, 0x5f, 0x52, 0x45, 0x43, 0x56, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x51, - 0x55, 0x41, 0x4c, 0x49, 0x46, 0x59, 0x10, 0x06, 0x32, 0x71, 0x0a, 0x0b, 0x50, 0x72, 0x69, 0x63, - 0x65, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x12, 0x62, 0x0a, 0x0f, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x12, 0x26, 0x2e, 0x70, 0x72, 0x69, - 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, - 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, - 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3f, 0x5a, 0x3d, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, - 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x70, 0x72, 0x6f, 0x6f, 0x74, 0x2d, - 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x2f, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, - 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x45, 0x5f, 0x51, 0x55, 0x41, 0x4c, 0x49, 0x46, 0x59, 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18, 0x49, + 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x43, 0x56, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, + 0x4e, 0x54, 0x5f, 0x48, 0x49, 0x4e, 0x54, 0x10, 0x04, 0x12, 0x17, 0x0a, 0x13, 0x49, 0x4e, 0x54, + 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x43, 0x56, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, + 0x10, 0x05, 0x12, 0x1f, 0x0a, 0x1b, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x43, + 0x56, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x51, 0x55, 0x41, 0x4c, 0x49, 0x46, + 0x59, 0x10, 0x06, 0x2a, 0x57, 0x0a, 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, + 0x12, 0x21, 0x0a, 0x1d, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, + 0x4f, 0x52, 0x41, 0x43, 0x4c, 0x45, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, + 0x45, 0x10, 0x00, 0x12, 0x27, 0x0a, 0x23, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, + 0x45, 0x44, 0x5f, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x4f, 0x52, 0x41, 0x43, 0x4c, 0x45, 0x5f, + 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x10, 0x01, 0x32, 0x71, 0x0a, 0x0b, + 0x50, 0x72, 0x69, 0x63, 0x65, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x12, 0x62, 0x0a, 0x0f, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x12, 0x26, + 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, + 0x3f, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, + 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x70, 0x72, + 0x6f, 0x6f, 0x74, 0x2d, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x2f, 0x74, 0x61, 0x70, 0x72, 0x70, + 0x63, 0x2f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -920,37 +978,39 @@ func file_priceoraclerpc_price_oracle_proto_rawDescGZIP() []byte { return file_priceoraclerpc_price_oracle_proto_rawDescData } -var file_priceoraclerpc_price_oracle_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_priceoraclerpc_price_oracle_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_priceoraclerpc_price_oracle_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_priceoraclerpc_price_oracle_proto_goTypes = []any{ (TransactionType)(0), // 0: priceoraclerpc.TransactionType (Intent)(0), // 1: priceoraclerpc.Intent - (*FixedPoint)(nil), // 2: priceoraclerpc.FixedPoint - (*AssetRates)(nil), // 3: priceoraclerpc.AssetRates - (*AssetSpecifier)(nil), // 4: priceoraclerpc.AssetSpecifier - (*QueryAssetRatesRequest)(nil), // 5: priceoraclerpc.QueryAssetRatesRequest - (*QueryAssetRatesOkResponse)(nil), // 6: priceoraclerpc.QueryAssetRatesOkResponse - (*QueryAssetRatesErrResponse)(nil), // 7: priceoraclerpc.QueryAssetRatesErrResponse - (*QueryAssetRatesResponse)(nil), // 8: priceoraclerpc.QueryAssetRatesResponse + (ErrorCode)(0), // 2: priceoraclerpc.ErrorCode + (*FixedPoint)(nil), // 3: priceoraclerpc.FixedPoint + (*AssetRates)(nil), // 4: priceoraclerpc.AssetRates + (*AssetSpecifier)(nil), // 5: priceoraclerpc.AssetSpecifier + (*QueryAssetRatesRequest)(nil), // 6: priceoraclerpc.QueryAssetRatesRequest + (*QueryAssetRatesOkResponse)(nil), // 7: priceoraclerpc.QueryAssetRatesOkResponse + (*QueryAssetRatesErrResponse)(nil), // 8: priceoraclerpc.QueryAssetRatesErrResponse + (*QueryAssetRatesResponse)(nil), // 9: priceoraclerpc.QueryAssetRatesResponse } var file_priceoraclerpc_price_oracle_proto_depIdxs = []int32{ - 2, // 0: priceoraclerpc.AssetRates.subjectAssetRate:type_name -> priceoraclerpc.FixedPoint - 2, // 1: priceoraclerpc.AssetRates.paymentAssetRate:type_name -> priceoraclerpc.FixedPoint + 3, // 0: priceoraclerpc.AssetRates.subjectAssetRate:type_name -> priceoraclerpc.FixedPoint + 3, // 1: priceoraclerpc.AssetRates.paymentAssetRate:type_name -> priceoraclerpc.FixedPoint 0, // 2: priceoraclerpc.QueryAssetRatesRequest.transaction_type:type_name -> priceoraclerpc.TransactionType - 4, // 3: priceoraclerpc.QueryAssetRatesRequest.subject_asset:type_name -> priceoraclerpc.AssetSpecifier - 4, // 4: priceoraclerpc.QueryAssetRatesRequest.payment_asset:type_name -> priceoraclerpc.AssetSpecifier - 3, // 5: priceoraclerpc.QueryAssetRatesRequest.asset_rates_hint:type_name -> priceoraclerpc.AssetRates + 5, // 3: priceoraclerpc.QueryAssetRatesRequest.subject_asset:type_name -> priceoraclerpc.AssetSpecifier + 5, // 4: priceoraclerpc.QueryAssetRatesRequest.payment_asset:type_name -> priceoraclerpc.AssetSpecifier + 4, // 5: priceoraclerpc.QueryAssetRatesRequest.asset_rates_hint:type_name -> priceoraclerpc.AssetRates 1, // 6: priceoraclerpc.QueryAssetRatesRequest.intent:type_name -> priceoraclerpc.Intent - 3, // 7: priceoraclerpc.QueryAssetRatesOkResponse.asset_rates:type_name -> priceoraclerpc.AssetRates - 6, // 8: priceoraclerpc.QueryAssetRatesResponse.ok:type_name -> priceoraclerpc.QueryAssetRatesOkResponse - 7, // 9: priceoraclerpc.QueryAssetRatesResponse.error:type_name -> priceoraclerpc.QueryAssetRatesErrResponse - 5, // 10: priceoraclerpc.PriceOracle.QueryAssetRates:input_type -> priceoraclerpc.QueryAssetRatesRequest - 8, // 11: priceoraclerpc.PriceOracle.QueryAssetRates:output_type -> priceoraclerpc.QueryAssetRatesResponse - 11, // [11:12] is the sub-list for method output_type - 10, // [10:11] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 4, // 7: priceoraclerpc.QueryAssetRatesOkResponse.asset_rates:type_name -> priceoraclerpc.AssetRates + 2, // 8: priceoraclerpc.QueryAssetRatesErrResponse.code:type_name -> priceoraclerpc.ErrorCode + 7, // 9: priceoraclerpc.QueryAssetRatesResponse.ok:type_name -> priceoraclerpc.QueryAssetRatesOkResponse + 8, // 10: priceoraclerpc.QueryAssetRatesResponse.error:type_name -> priceoraclerpc.QueryAssetRatesErrResponse + 6, // 11: priceoraclerpc.PriceOracle.QueryAssetRates:input_type -> priceoraclerpc.QueryAssetRatesRequest + 9, // 12: priceoraclerpc.PriceOracle.QueryAssetRates:output_type -> priceoraclerpc.QueryAssetRatesResponse + 12, // [12:13] is the sub-list for method output_type + 11, // [11:12] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_priceoraclerpc_price_oracle_proto_init() } @@ -1059,7 +1119,7 @@ func file_priceoraclerpc_price_oracle_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_priceoraclerpc_price_oracle_proto_rawDesc, - NumEnums: 2, + NumEnums: 3, NumMessages: 7, NumExtensions: 0, NumServices: 1, diff --git a/taprpc/priceoraclerpc/price_oracle.proto b/taprpc/priceoraclerpc/price_oracle.proto index 128ca4ae5..c2fd14e23 100644 --- a/taprpc/priceoraclerpc/price_oracle.proto +++ b/taprpc/priceoraclerpc/price_oracle.proto @@ -81,6 +81,17 @@ enum Intent { INTENT_RECV_PAYMENT_QUALIFY = 6; } +// ErrorCode represents the possible error codes that can be returned in a +// QueryAssetRatesErrResponse. +enum ErrorCode { + // UNSPECIFIED_ORACLE_ERROR_CODE indicates an unspecified error. + UNSPECIFIED_ORACLE_ERROR_CODE = 0; + + // UNSUPPORTED_ASSET_ORACLE_ERROR_CODE indicates the asset is not + // supported. + UNSUPPORTED_ASSET_ORACLE_ERROR_CODE = 1; +} + // FixedPoint is a scaled integer representation of a fractional number. // // This type consists of two integer fields: a coefficient and a scale. @@ -228,7 +239,7 @@ message QueryAssetRatesErrResponse { string message = 1; // code is the error code. - uint32 code = 2; + ErrorCode code = 2; } // QueryAssetRatesResponse is the response from a QueryAssetRates RPC call. diff --git a/taprpc/priceoraclerpc/price_oracle.swagger.json b/taprpc/priceoraclerpc/price_oracle.swagger.json index 04044cb66..317da5bc4 100644 --- a/taprpc/priceoraclerpc/price_oracle.swagger.json +++ b/taprpc/priceoraclerpc/price_oracle.swagger.json @@ -244,6 +244,15 @@ }, "description": "AssetSpecifier is a union type for specifying an asset by either its asset ID\nor group key." }, + "priceoraclerpcErrorCode": { + "type": "string", + "enum": [ + "UNSPECIFIED_ORACLE_ERROR_CODE", + "UNSUPPORTED_ASSET_ORACLE_ERROR_CODE" + ], + "default": "UNSPECIFIED_ORACLE_ERROR_CODE", + "description": "ErrorCode represents the possible error codes that can be returned in a\nQueryAssetRatesErrResponse.\n\n - UNSPECIFIED_ORACLE_ERROR_CODE: UNSPECIFIED_ORACLE_ERROR_CODE indicates an unspecified error.\n - UNSUPPORTED_ASSET_ORACLE_ERROR_CODE: UNSUPPORTED_ASSET_ORACLE_ERROR_CODE indicates the asset is not\nsupported." + }, "priceoraclerpcFixedPoint": { "type": "object", "properties": { @@ -281,8 +290,7 @@ "description": "error is the error message." }, "code": { - "type": "integer", - "format": "int64", + "$ref": "#/definitions/priceoraclerpcErrorCode", "description": "code is the error code." } },