From e85fa8d4d277a3244b056abf6ffc77fc3efd369a Mon Sep 17 00:00:00 2001 From: ffranr Date: Mon, 30 Sep 2024 13:26:40 +0100 Subject: [PATCH 01/14] rfqmath: add BigInt.String method This commit introduces the `BigInt.String` method, which can be used to safely (without overflow) export a `BigInt` to RPC or JSON. --- rfqmath/arithmetic.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/rfqmath/arithmetic.go b/rfqmath/arithmetic.go index 55ba153c0..3b92357e6 100644 --- a/rfqmath/arithmetic.go +++ b/rfqmath/arithmetic.go @@ -221,6 +221,13 @@ func (b BigInt) ToUint64() uint64 { return b.value.Uint64() } +// String returns the decimal representation of the BigInt as a string. +// It provides a human-readable format suitable for use in RPC messages and JSON +// serialization. +func (b BigInt) String() string { + return b.value.String() +} + // Equals returns true if the two integers are equal. func (b BigInt) Equals(other BigInt) bool { return b.value.Cmp(other.value) == 0 From 070d651578fd3b22585a3b7c1246534ad4e674a8 Mon Sep 17 00:00:00 2001 From: ffranr Date: Mon, 30 Sep 2024 14:15:27 +0100 Subject: [PATCH 02/14] rfqmath: add BigIntFixedPoint type alias This commit introduces a type alias for a fixed-point type where the coefficient is a `big.Int`. --- rfqmath/fixed_point.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/rfqmath/fixed_point.go b/rfqmath/fixed_point.go index 5a11e7797..0764e298f 100644 --- a/rfqmath/fixed_point.go +++ b/rfqmath/fixed_point.go @@ -3,6 +3,7 @@ package rfqmath import ( "fmt" "math" + "math/big" "strconv" ) @@ -167,3 +168,16 @@ func FixedPointFromUint64[N Int[N]](value uint64, scale uint8) FixedPoint[N] { Scale: scale, } } + +// BigIntFixedPoint is a fixed-point number with a BigInt coefficient. +type BigIntFixedPoint = FixedPoint[BigInt] + +// NewBigIntFixedPoint creates a new BigInt fixed-point given a coefficient and +// scale. +func NewBigIntFixedPoint(coefficient uint64, scale uint8) BigIntFixedPoint { + cBigInt := new(big.Int).SetUint64(coefficient) + return BigIntFixedPoint{ + Coefficient: NewBigInt(cBigInt), + Scale: scale, + } +} From 74fd6f8a85df531cca25c5fbb2f91ad5638d3dbd Mon Sep 17 00:00:00 2001 From: ffranr Date: Mon, 30 Sep 2024 14:16:01 +0100 Subject: [PATCH 03/14] rfqmsg: add MilliSatPerBtc constant This commit introduces a `big.Int` fixed-point constant representing the number of milli-satoshis in one BTC. --- rfqmsg/messages.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rfqmsg/messages.go b/rfqmsg/messages.go index 1111b26e9..19741c493 100644 --- a/rfqmsg/messages.go +++ b/rfqmsg/messages.go @@ -8,6 +8,7 @@ import ( "io" "math" + "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/tlv" @@ -73,9 +74,13 @@ const ( ) var ( - // ErrUnknownMessageType is an error that is returned when an unknown - // message type is encountered. + // ErrUnknownMessageType is an error returned when an unknown message + // type is encountered. ErrUnknownMessageType = errors.New("unknown message type") + + // MilliSatPerBtc is the number of milli-satoshis in one bitcoin: + // 100 billion = 100 * (10^9). + MilliSatPerBtc = rfqmath.FixedPointFromUint64[rfqmath.BigInt](100, 9) ) // WireMessage is a struct that represents a general wire message. From 4e291e5e6d370bb0f40eafbfec465c63658f72b6 Mon Sep 17 00:00:00 2001 From: ffranr Date: Tue, 24 Sep 2024 12:26:34 +0100 Subject: [PATCH 04/14] multi: RFQ price oracle returns asset rates as fixed-point numbers This commit updates the RFQ price oracle's `QueryRateTick` endpoint to return asset-to-BTC conversion rates as fixed-point numbers. --- docs/examples/basic-price-oracle/go.mod | 168 ++- docs/examples/basic-price-oracle/go.sum | 1034 ++++++++++++++++- docs/examples/basic-price-oracle/main.go | 66 +- rfq/cli.go | 1 + rfq/negotiator.go | 121 +- rfq/oracle.go | 150 ++- rfq/oracle_test.go | 37 +- tapcfg/server.go | 5 +- taprpc/priceoraclerpc/marshal.go | 30 + taprpc/priceoraclerpc/price_oracle.pb.go | 379 ++++-- taprpc/priceoraclerpc/price_oracle.proto | 51 +- .../priceoraclerpc/price_oracle.swagger.json | 56 +- 12 files changed, 1828 insertions(+), 270 deletions(-) diff --git a/docs/examples/basic-price-oracle/go.mod b/docs/examples/basic-price-oracle/go.mod index 1909f32cc..e98516b24 100644 --- a/docs/examples/basic-price-oracle/go.mod +++ b/docs/examples/basic-price-oracle/go.mod @@ -4,7 +4,13 @@ go 1.22 toolchain go1.22.3 -replace github.com/lightninglabs/taproot-assets => ../../../ +replace ( + github.com/lightninglabs/taproot-assets => ../../../ + + // We want to format raw bytes as hex instead of base64. The forked version + // allows us to specify that as an option. + google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-display v1.33.0-hex-display +) require ( github.com/lightninglabs/taproot-assets v0.0.0 @@ -12,13 +18,171 @@ require ( ) require ( + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect + github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect + github.com/aead/siphash v1.0.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/btcsuite/btcd v0.24.2-beta.rc1.0.20240403021926-ae5533602c46 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect + github.com/btcsuite/btcd/btcutil v1.1.5 // indirect + github.com/btcsuite/btcd/btcutil/psbt v1.1.8 // indirect + github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect + github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect + github.com/btcsuite/btcwallet v0.16.10-0.20240410030101-6fe19a472a62 // indirect + github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4 // indirect + github.com/btcsuite/btcwallet/wallet/txrules v1.2.1 // indirect + github.com/btcsuite/btcwallet/wallet/txsizes v1.2.4 // indirect + github.com/btcsuite/btcwallet/walletdb v1.4.2 // indirect + github.com/btcsuite/btcwallet/wtxmgr v1.5.3 // indirect + github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect + github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect + github.com/btcsuite/winsvc v1.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/containerd/continuity v0.3.0 // indirect + github.com/coreos/go-semver v0.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.3.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/decred/dcrd/lru v1.1.2 // indirect + github.com/docker/cli v20.10.17+incompatible // indirect + github.com/docker/docker v24.0.7+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/fergusstrange/embedded-postgres v1.25.0 // indirect + github.com/go-errors/errors v1.0.1 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.4.2 // indirect + github.com/golang-migrate/migrate/v4 v4.17.0 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/btree v1.0.1 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/pgconn v1.14.3 // indirect + github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438 // indirect + github.com/jackc/pgio v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgtype v1.14.0 // indirect + github.com/jackc/pgx/v4 v4.18.2 // indirect + github.com/jessevdk/go-flags v1.4.0 // indirect + github.com/jonboulle/clockwork v0.2.2 // indirect + github.com/jrick/logrotate v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/juju/loggo v0.0.0-20210728185423-eebad3a902c4 // indirect + github.com/kkdai/bstream v1.0.0 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf // indirect + github.com/lightninglabs/lndclient v1.0.1-0.20240725080034-64a756aa4c36 // indirect + github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd // indirect + github.com/lightninglabs/neutrino/cache v1.1.2 // indirect + github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f // indirect + github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240919091721-70580403898e // indirect + github.com/lightningnetwork/lnd/clock v1.1.1 // indirect + github.com/lightningnetwork/lnd/fn v1.1.0 // indirect + github.com/lightningnetwork/lnd/healthcheck v1.2.4 // indirect + github.com/lightningnetwork/lnd/kvdb v1.4.8 // indirect + github.com/lightningnetwork/lnd/queue v1.1.1 // indirect + github.com/lightningnetwork/lnd/sqldb v1.0.2 // indirect + github.com/lightningnetwork/lnd/ticker v1.1.1 // indirect + github.com/lightningnetwork/lnd/tlv v1.2.6 // indirect + github.com/lightningnetwork/lnd/tor v1.1.2 // indirect + github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/miekg/dns v1.1.50 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/opencontainers/runc v1.1.12 // indirect + github.com/ory/dockertest/v3 v3.10.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rogpeppe/fastuuid v1.2.0 // indirect + github.com/sirupsen/logrus v1.9.2 // indirect + github.com/soheilhy/cmux v0.1.5 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/testify v1.9.0 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect + github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect + go.etcd.io/bbolt v1.3.8 // indirect + go.etcd.io/etcd/api/v3 v3.5.12 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect + go.etcd.io/etcd/client/v2 v2.305.12 // indirect + go.etcd.io/etcd/client/v3 v3.5.12 // indirect + go.etcd.io/etcd/pkg/v3 v3.5.12 // indirect + go.etcd.io/etcd/raft/v3 v3.5.12 // indirect + go.etcd.io/etcd/server/v3 v3.5.12 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 // indirect + go.opentelemetry.io/otel v1.20.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 // indirect + go.opentelemetry.io/otel/metric v1.20.0 // indirect + go.opentelemetry.io/otel/sdk v1.20.0 // indirect + go.opentelemetry.io/otel/trace v1.20.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.23.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect + golang.org/x/mod v0.16.0 // indirect golang.org/x/net v0.23.0 // indirect + golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.19.0 // indirect + google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/errgo.v1 v1.0.1 // indirect + gopkg.in/macaroon-bakery.v2 v2.1.0 // indirect + gopkg.in/macaroon.v2 v2.1.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect + modernc.org/libc v1.50.9 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.8.0 // indirect + modernc.org/sqlite v1.30.0 // indirect + modernc.org/strutil v1.2.0 // indirect + modernc.org/token v1.1.0 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect ) diff --git a/docs/examples/basic-price-oracle/go.sum b/docs/examples/basic-price-oracle/go.sum index ab124ac0f..943356925 100644 --- a/docs/examples/basic-price-oracle/go.sum +++ b/docs/examples/basic-price-oracle/go.sum @@ -1,24 +1,1054 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= +github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= +github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= +github.com/btcsuite/btcd v0.24.2-beta.rc1.0.20240403021926-ae5533602c46 h1:tjpNTdZNQqE14menwDGAxWfzN0DFHVTXFEyEL8yvA/4= +github.com/btcsuite/btcd v0.24.2-beta.rc1.0.20240403021926-ae5533602c46/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= +github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= +github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= +github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= +github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= +github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= +github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= +github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= +github.com/btcsuite/btcd/btcutil/psbt v1.1.8 h1:4voqtT8UppT7nmKQkXV+T9K8UyQjKOn2z/ycpmJK8wg= +github.com/btcsuite/btcd/btcutil/psbt v1.1.8/go.mod h1:kA6FLH/JfUx++j9pYU0pyu+Z8XGBQuuTmuKYUf6q7/U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcwallet v0.16.10-0.20240410030101-6fe19a472a62 h1:MtcTVTcDbGdTJhfDc7LLikojyl0PYtSRNLwoRaLVbWI= +github.com/btcsuite/btcwallet v0.16.10-0.20240410030101-6fe19a472a62/go.mod h1:2C3Q/MhYAKmk7F+Tey6LfKtKRTdQsrCf8AAAzzDPmH4= +github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4 h1:poyHFf7+5+RdxNp5r2T6IBRD7RyraUsYARYbp/7t4D8= +github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4/go.mod h1:GETGDQuyq+VFfH1S/+/7slLM/9aNa4l7P4ejX6dJfb0= +github.com/btcsuite/btcwallet/wallet/txrules v1.2.1 h1:UZo7YRzdHbwhK7Rhv3PO9bXgTxiOH45edK5qdsdiatk= +github.com/btcsuite/btcwallet/wallet/txrules v1.2.1/go.mod h1:MVSqRkju/IGxImXYPfBkG65FgEZYA4fXchheILMVl8g= +github.com/btcsuite/btcwallet/wallet/txsizes v1.2.4 h1:nmcKAVTv/cmYrs0A4hbiC6Qw+WTLYy/14SmTt3mLnCo= +github.com/btcsuite/btcwallet/wallet/txsizes v1.2.4/go.mod h1:YqJR8WAAHiKIPesZTr9Cx9Az4fRhRLcJ6GcxzRUZCAc= +github.com/btcsuite/btcwallet/walletdb v1.4.2 h1:zwZZ+zaHo4mK+FAN6KeK85S3oOm+92x2avsHvFAhVBE= +github.com/btcsuite/btcwallet/walletdb v1.4.2/go.mod h1:7ZQ+BvOEre90YT7eSq8bLoxTsgXidUzA/mqbRS114CQ= +github.com/btcsuite/btcwallet/wtxmgr v1.5.3 h1:QrWCio9Leh3DwkWfp+A1SURj8pYn3JuTLv3waP5uEro= +github.com/btcsuite/btcwallet/wtxmgr v1.5.3/go.mod h1:M4nQpxGTXiDlSOODKXboXX7NFthmiBNjzAKKNS7Fhjg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= +github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/decred/dcrd/lru v1.1.2 h1:KdCzlkxppuoIDGEvCGah1fZRicrDH36IipvlB1ROkFY= +github.com/decred/dcrd/lru v1.1.2/go.mod h1:gEdCVgXs1/YoBvFWt7Scgknbhwik3FgVSzlnCcXL2N8= +github.com/dhui/dktest v0.4.0 h1:z05UmuXZHO/bgj/ds2bGMBu8FI4WA+Ag/m3ghL+om7M= +github.com/dhui/dktest v0.4.0/go.mod h1:v/Dbz1LgCBOi2Uki2nUqLBGa83hWBGFMu5MrgMDCc78= +github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M= +github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= +github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/fergusstrange/embedded-postgres v1.25.0 h1:sa+k2Ycrtz40eCRPOzI7Ry7TtkWXXJ+YRsxpKMDhxK0= +github.com/fergusstrange/embedded-postgres v1.25.0/go.mod h1:t/MLs0h9ukYM6FSt99R7InCHs1nW0ordoVCcnzmpTYw= +github.com/frankban/quicktest v1.0.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k= +github.com/frankban/quicktest v1.2.2 h1:xfmOhhoH5fGPgbEAlhLpJH9p0z/0Qizio9osmvn9IUY= +github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-migrate/migrate/v4 v4.17.0 h1:rd40H3QXU0AA4IoLllFcEAEo9dYKRHYND2gB4p7xcaU= +github.com/golang-migrate/migrate/v4 v4.17.0/go.mod h1:+Cp2mtLP4/aXDTKb9wmXYitdrNx2HGs45rbWAo6OsKM= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= +github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438 h1:Dj0L5fhJ9F82ZJyVOmBx6msDp/kfd1t9GRfny/mfJA0= +github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= +github.com/juju/clock v0.0.0-20220203021603-d9deb868a28a h1:Az/6CM/P5guGHNy7r6TkOCctv3lDmN3W1uhku7QMupk= +github.com/juju/clock v0.0.0-20220203021603-d9deb868a28a/go.mod h1:GZ/FY8Cqw3KHG6DwRVPUKbSPTAwyrU28xFi5cqZnLsc= +github.com/juju/collections v0.0.0-20220203020748-febd7cad8a7a h1:d7eZO8OS/ZXxdP0uq3E8CdoA1qNFaecAv90UxrxaY2k= +github.com/juju/collections v0.0.0-20220203020748-febd7cad8a7a/go.mod h1:JWeZdyttIEbkR51z2S13+J+aCuHVe0F6meRy+P0YGDo= +github.com/juju/errors v0.0.0-20220331221717-b38fca44723b h1:AxFeSQJfcm2O3ov1wqAkTKYFsnMw2g1B4PkYujfAdkY= +github.com/juju/errors v0.0.0-20220331221717-b38fca44723b/go.mod h1:jMGj9DWF/qbo91ODcfJq6z/RYc3FX3taCBZMCcpI4Ls= +github.com/juju/loggo v0.0.0-20210728185423-eebad3a902c4 h1:NO5tuyw++EGLnz56Q8KMyDZRwJwWO8jQnj285J3FOmY= +github.com/juju/loggo v0.0.0-20210728185423-eebad3a902c4/go.mod h1:NIXFioti1SmKAlKNuUwbMenNdef59IF52+ZzuOmHYkg= +github.com/juju/mgo/v2 v2.0.0-20220111072304-f200228f1090 h1:zX5GoH3Jp8k1EjUFkApu/YZAYEn0PYQfg/U6IDyNyYs= +github.com/juju/mgo/v2 v2.0.0-20220111072304-f200228f1090/go.mod h1:N614SE0a4e+ih2rg96Vi2PeC3cTpUOWgCTv3Cgk974c= +github.com/juju/retry v0.0.0-20220204093819-62423bf33287 h1:U+7oMWEglXfiikIppNexButZRwKPlzLBGKYSNCXzXf8= +github.com/juju/retry v0.0.0-20220204093819-62423bf33287/go.mod h1:SssN1eYeK3A2qjnFGTiVMbdzGJ2BfluaJblJXvuvgqA= +github.com/juju/testing v0.0.0-20220203020004-a0ff61f03494 h1:XEDzpuZb8Ma7vLja3+5hzUqVTvAqm5Y+ygvnDs5iTMM= +github.com/juju/testing v0.0.0-20220203020004-a0ff61f03494/go.mod h1:rUquetT0ALL48LHZhyRGvjjBH8xZaZ8dFClulKK5wK4= +github.com/juju/utils/v3 v3.0.0-20220203023959-c3fbc78a33b0 h1:bn+2Adl1yWqYjm3KSFlFqsvfLg2eq+XNL7GGMYApdVw= +github.com/juju/utils/v3 v3.0.0-20220203023959-c3fbc78a33b0/go.mod h1:8csUcj1VRkfjNIRzBFWzLFCMLwLqsRWvkmhfVAUwbC4= +github.com/juju/version/v2 v2.0.0-20220204124744-fc9915e3d935 h1:6YoyzXVW1XkqN86y2s/rz365Jm7EiAy39v2G5ikzvHU= +github.com/juju/version/v2 v2.0.0-20220204124744-fc9915e3d935/go.mod h1:ZeFjNy+UFEWJDDPdzW7Cm9NeU6dsViGaFYhXzycLQrw= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kkdai/bstream v1.0.0 h1:Se5gHwgp2VT2uHfDrkbbgbgEvV9cimLELwrPJctSjg8= +github.com/kkdai/bstream v1.0.0/go.mod h1:FDnDOHt5Yx4p3FaHcioFT0QjDOtgUpvjeZqAs+NVZZA= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc= +github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= +github.com/lightninglabs/lightning-node-connect v0.2.5-alpha h1:ZRVChwczFXK0CEbxOCWwUA6TIZvrkE0APd1T3WjFAwg= +github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2 h1:Er1miPZD2XZwcfE4xoS5AILqP1mj7kqnhbBSxW9BDxY= +github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2/go.mod h1:antQGRDRJiuyQF6l+k6NECCSImgCpwaZapATth2Chv4= +github.com/lightninglabs/lndclient v1.0.1-0.20240725080034-64a756aa4c36 h1:gfJ3TOuqSnuXEo1Boj1H9P6tpxPSH9cvi+rB10L0svI= +github.com/lightninglabs/lndclient v1.0.1-0.20240725080034-64a756aa4c36/go.mod h1:bxd2a15cIaW8KKcmOf9nNDI/GTxxj0upEYs1EIkttqw= +github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd h1:D8aRocHpoCv43hL8egXEMYyPmyOiefFHZ66338KQB2s= +github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd/go.mod h1:x3OmY2wsA18+Kc3TSV2QpSUewOCiscw2mKpXgZv2kZk= +github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3shmlu5hIQ798g= +github.com/lightninglabs/neutrino/cache v1.1.2/go.mod h1:XJNcgdOw1LQnanGjw8Vj44CvguYA25IMKjWFZczwZuo= +github.com/lightninglabs/protobuf-go-hex-display v1.33.0-hex-display h1:Y2WiPkBS/00EiEg0qp0FhehxnQfk3vv8U6Xt3nN+rTY= +github.com/lightninglabs/protobuf-go-hex-display v1.33.0-hex-display/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f h1:Pua7+5TcFEJXIIZ1I2YAUapmbcttmLj4TTi786bIi3s= +github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI= +github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240919091721-70580403898e h1:Weu9TWNEIpC4XLbcUoSFK3Pv2aUSwn7NlYZKdsm8wUU= +github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240919091721-70580403898e/go.mod h1:/Uh0qCiU/oQls68spxpmP0kRjX/uGkLzt7P/uPpDofE= +github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0= +github.com/lightningnetwork/lnd/clock v1.1.1/go.mod h1:mGnAhPyjYZQJmebS7aevElXKTFDuO+uNFFfMXK1W8xQ= +github.com/lightningnetwork/lnd/fn v1.1.0 h1:W1p/bUXMgAh5YlmawdQYaNgmLaLMT77BilepzWOSZ2A= +github.com/lightningnetwork/lnd/fn v1.1.0/go.mod h1:P027+0CyELd92H9gnReUkGGAqbFA1HwjHWdfaDFD51U= +github.com/lightningnetwork/lnd/healthcheck v1.2.4 h1:lLPLac+p/TllByxGSlkCwkJlkddqMP5UCoawCj3mgFQ= +github.com/lightningnetwork/lnd/healthcheck v1.2.4/go.mod h1:G7Tst2tVvWo7cx6mSBEToQC5L1XOGxzZTPB29g9Rv2I= +github.com/lightningnetwork/lnd/kvdb v1.4.8 h1:xH0a5Vi1yrcZ5BEeF2ba3vlKBRxrL9uYXlWTjOjbNTY= +github.com/lightningnetwork/lnd/kvdb v1.4.8/go.mod h1:J2diNABOoII9UrMnxXS5w7vZwP7CA1CStrl8MnIrb3A= +github.com/lightningnetwork/lnd/queue v1.1.1 h1:99ovBlpM9B0FRCGYJo6RSFDlt8/vOkQQZznVb18iNMI= +github.com/lightningnetwork/lnd/queue v1.1.1/go.mod h1:7A6nC1Qrm32FHuhx/mi1cieAiBZo5O6l8IBIoQxvkz4= +github.com/lightningnetwork/lnd/sqldb v1.0.2 h1:PfuYzScYMD9/QonKo/QvgsbXfTnH5DfldIimkfdW4Bk= +github.com/lightningnetwork/lnd/sqldb v1.0.2/go.mod h1:V2Xl6JNWLTKE97WJnwfs0d0TYJdIQTqK8/3aAwkd3qI= +github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM= +github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA= +github.com/lightningnetwork/lnd/tlv v1.2.6 h1:icvQG2yDr6k3ZuZzfRdG3EJp6pHurcuh3R6dg0gv/Mw= +github.com/lightningnetwork/lnd/tlv v1.2.6/go.mod h1:/CmY4VbItpOldksocmGT4lxiJqRP9oLxwSZOda2kzNQ= +github.com/lightningnetwork/lnd/tor v1.1.2 h1:3zv9z/EivNFaMF89v3ciBjCS7kvCj4ZFG7XvD2Qq0/k= +github.com/lightningnetwork/lnd/tor v1.1.2/go.mod h1:j7T9uJ2NLMaHwE7GiBGnpYLn4f7NRoTM6qj+ul6/ycA= +github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw= +github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY= +github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA= +github.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/mattn/go-colorable v0.0.6/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.0-20160806122752-66b8e73f3f5c/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= +github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss= +github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= +github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c= +go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= +go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A= +go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= +go.etcd.io/etcd/client/v2 v2.305.12 h1:0m4ovXYo1CHaA/Mp3X/Fak5sRNIWf01wk/X1/G3sGKI= +go.etcd.io/etcd/client/v2 v2.305.12/go.mod h1:aQ/yhsxMu+Oht1FOupSr60oBvcS9cKXHrzBpDsPTf9E= +go.etcd.io/etcd/client/v3 v3.5.12 h1:v5lCPXn1pf1Uu3M4laUE2hp/geOTc5uPcYYsNe1lDxg= +go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw= +go.etcd.io/etcd/pkg/v3 v3.5.12 h1:OK2fZKI5hX/+BTK76gXSTyZMrbnARyX9S643GenNGb8= +go.etcd.io/etcd/pkg/v3 v3.5.12/go.mod h1:UVwg/QIMoJncyeb/YxvJBJCE/NEwtHWashqc8A1nj/M= +go.etcd.io/etcd/raft/v3 v3.5.12 h1:7r22RufdDsq2z3STjoR7Msz6fYH8tmbkdheGfwJNRmU= +go.etcd.io/etcd/raft/v3 v3.5.12/go.mod h1:ERQuZVe79PI6vcC3DlKBukDCLja/L7YMu29B74Iwj4U= +go.etcd.io/etcd/server/v3 v3.5.12 h1:EtMjsbfyfkwZuA2JlKOiBfuGkFCekv5H178qjXypbG8= +go.etcd.io/etcd/server/v3 v3.5.12/go.mod h1:axB0oCjMy+cemo5290/CutIjoxlfA6KVYKD1w0uue10= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 h1:PzIubN4/sjByhDRHLviCjJuweBXWFZWhghjg7cS28+M= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0/go.mod h1:Ct6zzQEuGK3WpJs2n4dn+wfJYzd/+hNnxMRTWjGn30M= +go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc= +go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0/go.mod h1:vNUq47TGFioo+ffTSnKNdob241vePmtNZnAODKapKd0= +go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA= +go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM= +go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlAWGM= +go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0= +go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ= +go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= +golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v1 v1.0.1 h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso= +gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/macaroon-bakery.v2 v2.1.0 h1:9Jw/+9XHBSutkaeVpWhDx38IcSNLJwWUICkOK98DHls= +gopkg.in/macaroon-bakery.v2 v2.1.0/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA= +gopkg.in/macaroon.v2 v2.1.0 h1:HZcsjBCzq9t0eBPMKqTN/uSN6JOm78ZJ2INbqcBQOUI= +gopkg.in/macaroon.v2 v2.1.0/go.mod h1:OUb+TQP/OP0WOerC2Jp/3CwhIKyIa9kQjuc7H24e6/o= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo= +gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +modernc.org/cc/v4 v4.21.2 h1:dycHFB/jDc3IyacKipCNSDrjIC0Lm1hyoWOZTRR20Lk= +modernc.org/cc/v4 v4.21.2/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v4 v4.17.8 h1:yyWBf2ipA0Y9GGz/MmCmi3EFpKgeS7ICrAFes+suEbs= +modernc.org/ccgo/v4 v4.17.8/go.mod h1:buJnJ6Fn0tyAdP/dqePbrrvLyr6qslFfTbFrCuaYvtA= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= +modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.50.9 h1:hIWf1uz55lorXQhfoEoezdUHjxzuO6ceshET/yWjSjk= +modernc.org/libc v1.50.9/go.mod h1:15P6ublJ9FJR8YQCGy8DeQ2Uwur7iW9Hserr/T3OFZE= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= +modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= +modernc.org/sqlite v1.30.0 h1:8YhPUs/HTnlEgErn/jSYQTwHN/ex8CjHHjg+K9iG7LM= +modernc.org/sqlite v1.30.0/go.mod h1:cgkTARJ9ugeXSNaLBPK3CqbOe7Ec7ZhWPoMFGldEYEw= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= +pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/docs/examples/basic-price-oracle/main.go b/docs/examples/basic-price-oracle/main.go index 5838bea8c..0d8df9934 100644 --- a/docs/examples/basic-price-oracle/main.go +++ b/docs/examples/basic-price-oracle/main.go @@ -11,6 +11,8 @@ import ( "net" "time" + "github.com/lightninglabs/taproot-assets/rfqmath" + "github.com/lightninglabs/taproot-assets/rfqmsg" oraclerpc "github.com/lightninglabs/taproot-assets/taprpc/priceoraclerpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -45,18 +47,26 @@ func isSupportedSubjectAsset(subjectAsset *oraclerpc.AssetSpecifier) bool { // getRateTick returns a rate tick for a given transaction type and subject // asset max amount. func getRateTick(transactionType oraclerpc.TransactionType, - subjectAssetMaxAmount uint64) oraclerpc.RateTick { + subjectAssetMaxAmount uint64) (oraclerpc.RateTick, error) { // Determine the rate based on the transaction type. - var rate uint64 + var subjectAssetRate rfqmath.BigIntFixedPoint if transactionType == oraclerpc.TransactionType_PURCHASE { - // The rate for a purchase transaction is 42,000 asset units per - // mSAT. - rate = 42_000 + // As an example, the purchase rate is $42,000 per BTC. To + // increase precision, we represent this as 42 billion + // taproot asset units per BTC. Therefore, we scale the + // $42,000 per BTC rate by a factor of 10^6. + subjectAssetRate = rfqmath.FixedPointFromUint64[rfqmath.BigInt]( + 42_000, 6, + ) } else { - // The rate for a sale transaction is 40,000 asset units per - // mSAT. - rate = 40_000 + // Our example sell rate will be lower at $40,000 per BTC. This + // rate will be represented as 40 billion taproot asset units + // per BTC. Therefore, we scale the $40,000 per BTC rate by a + // factor of 10^6. + subjectAssetRate = rfqmath.FixedPointFromUint64[rfqmath.BigInt]( + 40_000, 6, + ) } // Set the rate expiry to 5 minutes by default. @@ -68,10 +78,27 @@ func getRateTick(transactionType oraclerpc.TransactionType, expiry = time.Now().Add(1 * time.Minute).Unix() } - return oraclerpc.RateTick{ - Rate: rate, - ExpiryTimestamp: uint64(expiry), + // Marshal subject asset rate to RPC format. + rpcSubjectAssetToBtcRate, err := oraclerpc.MarshalBigIntFixedPoint( + subjectAssetRate, + ) + if err != nil { + return oraclerpc.RateTick{}, err + } + + // Marshal payment asset rate to RPC format. + rpcPaymentAssetToBtcRate, err := oraclerpc.MarshalBigIntFixedPoint( + rfqmsg.MilliSatPerBtc, + ) + if err != nil { + return oraclerpc.RateTick{}, err } + + return oraclerpc.RateTick{ + SubjectAssetRate: rpcSubjectAssetToBtcRate, + PaymentAssetRate: rpcPaymentAssetToBtcRate, + ExpiryTimestamp: uint64(expiry), + }, nil } // QueryRateTick queries the rate tick for a given transaction type, subject @@ -133,20 +160,29 @@ func (p *RpcPriceOracleServer) QueryRateTick(_ context.Context, } // Determine which rate tick to return. - var rateTick oraclerpc.RateTick + var ( + rateTick oraclerpc.RateTick + err error + ) if req.RateTickHint != nil { // If a rate tick hint is provided, return it as the rate tick. // In doing so, we effectively accept the rate tick proposed by // our peer. - rateTick.Rate = req.RateTickHint.Rate - rateTick.ExpiryTimestamp = req.RateTickHint.ExpiryTimestamp + rateTick = oraclerpc.RateTick{ + SubjectAssetRate: req.RateTickHint.SubjectAssetRate, + PaymentAssetRate: req.RateTickHint.PaymentAssetRate, + ExpiryTimestamp: req.RateTickHint.ExpiryTimestamp, + } } else { // If a rate tick hint is not provided, fetch a rate tick from // our internal system. - rateTick = getRateTick( + rateTick, err = getRateTick( req.TransactionType, req.SubjectAssetMaxAmount, ) + if err != nil { + return nil, err + } } return &oraclerpc.QueryRateTickResponse{ diff --git a/rfq/cli.go b/rfq/cli.go index 3c4889b3e..c76c066a8 100644 --- a/rfq/cli.go +++ b/rfq/cli.go @@ -28,6 +28,7 @@ type CliConfig struct { MockOracleAssetsPerBTC uint64 `long:"mockoracleassetsperbtc" description:"Mock price oracle static asset units per BTC rate (for example number of USD cents per BTC if one asset unit represents a USD cent); whole numbers only, use either this or mockoraclesatsperasset depending on required precision"` + // TODO(ffranr): Remove in favour of MockOracleAssetsPerBTC. MockOracleSatsPerAsset uint64 `long:"mockoraclesatsperasset" description:"Mock price oracle static satoshis per asset unit rate (for example number of satoshis to pay for one USD cent if one asset unit represents a USD cent); whole numbers only, use either this or mockoracleassetsperbtc depending on required precision"` } diff --git a/rfq/negotiator.go b/rfq/negotiator.go index e0b36cfe2..98af38acd 100644 --- a/rfq/negotiator.go +++ b/rfq/negotiator.go @@ -9,6 +9,7 @@ import ( "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" @@ -107,7 +108,7 @@ func NewNegotiator(cfg NegotiatorCfg) (*Negotiator, error) { // an appropriate outgoing response message which should be sent to the peer. func (n *Negotiator) queryBidFromPriceOracle(peer route.Vertex, assetId *asset.ID, assetGroupKey *btcec.PublicKey, - assetAmount uint64) (lnwire.MilliSatoshi, uint64, error) { + assetAmount uint64) (*rfqmath.BigIntFixedPoint, uint64, error) { // TODO(ffranr): Optionally accept a peer's proposed ask price as an // arg to this func and pass it to the price oracle. The price oracle @@ -123,28 +124,28 @@ func (n *Negotiator) queryBidFromPriceOracle(peer route.Vertex, ctx, assetId, assetGroupKey, assetAmount, ) if err != nil { - return 0, 0, fmt.Errorf("failed to query price oracle for "+ + return nil, 0, fmt.Errorf("failed to query price oracle for "+ "bid: %w", err) } // 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 oracleResponse.Err != nil { - return 0, 0, fmt.Errorf("failed to query price oracle for "+ + return nil, 0, fmt.Errorf("failed to query price oracle for "+ "bid price: %s", oracleResponse.Err) } // By this point, the price oracle did not return an error or a bid // price. We will therefore return an error. - if oracleResponse.BidPrice == nil { - return 0, 0, fmt.Errorf("price oracle did not specify a bid " + - "price") + if oracleResponse.AssetRate.Coefficient.ToUint64() == 0 { + return nil, 0, fmt.Errorf("price oracle did not specify a " + + "bid price") } // TODO(ffranr): Check that the bid price is reasonable. // TODO(ffranr): Ensure that the expiry time is valid and sufficient. - return *oracleResponse.BidPrice, oracleResponse.Expiry, nil + return &oracleResponse.AssetRate, oracleResponse.Expiry, nil } // HandleOutgoingBuyOrder handles an outgoing buy order by constructing buy @@ -166,7 +167,7 @@ func (n *Negotiator) HandleOutgoingBuyOrder(buyOrder BuyOrder) error { if n.cfg.PriceOracle != nil { // Query the price oracle for a bid price. var err error - bidPrice, _, err = n.queryBidFromPriceOracle( + assetRate, _, err := n.queryBidFromPriceOracle( *buyOrder.Peer, buyOrder.AssetID, buyOrder.AssetGroupKey, buyOrder.MinAssetAmount, ) @@ -178,6 +179,13 @@ func (n *Negotiator) HandleOutgoingBuyOrder(buyOrder BuyOrder) error { "price oracle for outgoing buy "+ "request: %v", err) } + + // 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(), + ) } request, err := rfqmsg.NewBuyRequest( @@ -214,53 +222,39 @@ func (n *Negotiator) HandleOutgoingBuyOrder(buyOrder BuyOrder) error { // peer. func (n *Negotiator) queryAskFromPriceOracle(peer *route.Vertex, assetId *asset.ID, assetGroupKey *btcec.PublicKey, assetAmount uint64, - bid *lnwire.MilliSatoshi) (lnwire.MilliSatoshi, uint64, error) { + suggestedAssetRate fn.Option[rfqmath.BigIntFixedPoint]) ( + *rfqmath.BigIntFixedPoint, uint64, error) { // Query the price oracle for an asking price. ctx, cancel := n.WithCtxQuitNoTimeout() defer cancel() oracleResponse, err := n.cfg.PriceOracle.QueryAskPrice( - ctx, assetId, assetGroupKey, assetAmount, bid, + ctx, assetId, assetGroupKey, assetAmount, suggestedAssetRate, ) if err != nil { - return 0, 0, fmt.Errorf("failed to query price oracle for "+ + return nil, 0, fmt.Errorf("failed to query price oracle for "+ "ask price: %w", err) } // 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 oracleResponse.Err != nil { - return 0, 0, fmt.Errorf("failed to query price oracle for "+ + return nil, 0, fmt.Errorf("failed to query price oracle for "+ "ask price: %s", oracleResponse.Err) } // By this point, the price oracle did not return an error or an asking // price. We will therefore return an error. - if oracleResponse.AskPrice == nil { - return 0, 0, fmt.Errorf("price oracle did not specify an " + - "asking price") + if oracleResponse.AssetRate.Coefficient.ToUint64() == 0 { + return nil, 0, fmt.Errorf("price oracle did not specify an " + + "asset to BTC rate") } // TODO(ffranr): Check that the asking price is reasonable. // TODO(ffranr): Ensure that the expiry time is valid and sufficient. - // If the asking price is not nil, then we can proceed to compute a - // final asking price. - // - // If the bid price (bid price suggested in the buy request) is greater - // than the asking price, then we will use the bid price as the final - // asking price. Otherwise, we will use the asking price provided by the - // price oracle as the final asking price. - var finalAskPrice lnwire.MilliSatoshi - - if bid != nil && *bid > *oracleResponse.AskPrice { - finalAskPrice = *bid - } else { - finalAskPrice = *oracleResponse.AskPrice - } - - return finalAskPrice, oracleResponse.Expiry, nil + return &oracleResponse.AssetRate, oracleResponse.Expiry, nil } // HandleIncomingBuyRequest handles an incoming asset buy quote request. @@ -322,10 +316,22 @@ func (n *Negotiator) HandleIncomingBuyRequest( go func() { defer n.Wg.Done() + // 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. + var suggestedAssetRate fn.Option[rfqmath.BigIntFixedPoint] + if request.BidPrice > 0 { + suggestedAssetRate = fn.Some( + rfqmath.NewBigIntFixedPoint( + uint64(request.BidPrice), 0, + ), + ) + } + // Query the price oracle for an asking price. - askPrice, askExpiry, err := n.queryAskFromPriceOracle( + assetRate, rateExpiry, err := n.queryAskFromPriceOracle( nil, request.AssetID, request.AssetGroupKey, - request.AssetAmount, &request.BidPrice, + request.AssetAmount, suggestedAssetRate, ) if err != nil { // Send a reject message to the peer. @@ -343,8 +349,14 @@ func (n *Negotiator) HandleIncomingBuyRequest( } // Construct and send a buy 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. + askPrice := assetRate.Coefficient.ToUint64() + msg := rfqmsg.NewBuyAcceptFromRequest( - request, askPrice, askExpiry, + request, lnwire.MilliSatoshi(askPrice), rateExpiry, ) sendOutgoingMsg(msg) }() @@ -418,7 +430,7 @@ func (n *Negotiator) HandleIncomingSellRequest( // Query the price oracle for a bid price. This is the price we // are willing to pay for the asset that our peer is trying to // sell to us. - bidPrice, bidExpiry, err := n.queryBidFromPriceOracle( + assetRate, rateExpiry, err := n.queryBidFromPriceOracle( request.Peer, request.AssetID, request.AssetGroupKey, request.AssetAmount, ) @@ -438,8 +450,16 @@ 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, bidExpiry, + request, bidPrice, rateExpiry, ) sendOutgoingMsg(msg) }() @@ -466,9 +486,10 @@ func (n *Negotiator) HandleOutgoingSellOrder(order SellOrder) { if n.cfg.PriceOracle != nil { // Query the price oracle for an asking price. var err error - askPrice, _, err = n.queryAskFromPriceOracle( + assetRate, _, err := n.queryAskFromPriceOracle( order.Peer, order.AssetID, order.AssetGroupKey, - order.MaxAssetAmount, nil, + order.MaxAssetAmount, + fn.None[rfqmath.BigIntFixedPoint](), ) if err != nil { err := fmt.Errorf("negotiator failed to "+ @@ -476,6 +497,13 @@ func (n *Negotiator) HandleOutgoingSellOrder(order SellOrder) { n.cfg.ErrChan <- err return } + + // 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. + askPrice = lnwire.MilliSatoshi( + assetRate.Coefficient.ToUint64(), + ) } request, err := rfqmsg.NewSellRequest( @@ -610,9 +638,10 @@ func (n *Negotiator) HandleIncomingBuyAccept(msg rfqmsg.BuyAccept, // We will sanity check that price by querying our price oracle // for an ask price. We will then compare the ask price returned // by the price oracle with the ask price provided by the peer. - oraclePrice, _, err := n.queryAskFromPriceOracle( + assetRate, _, err := n.queryAskFromPriceOracle( &msg.Peer, msg.Request.AssetID, nil, - msg.Request.AssetAmount, nil, + msg.Request.AssetAmount, + fn.None[rfqmath.BigIntFixedPoint](), ) if err != nil { // The price oracle returned an error. We will return @@ -638,6 +667,11 @@ func (n *Negotiator) HandleIncomingBuyAccept(msg rfqmsg.BuyAccept, 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( @@ -731,7 +765,7 @@ func (n *Negotiator) HandleIncomingSellAccept(msg rfqmsg.SellAccept, // We will sanity check that price by querying our price oracle // for a bid price. We will then compare the bid price returned // by the price oracle with the bid price provided by the peer. - oraclePrice, _, err := n.queryBidFromPriceOracle( + assetRate, _, err := n.queryBidFromPriceOracle( msg.Peer, msg.Request.AssetID, nil, msg.Request.AssetAmount, ) @@ -759,6 +793,11 @@ 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( diff --git a/rfq/oracle.go b/rfq/oracle.go index d2423b553..10f389bed 100644 --- a/rfq/oracle.go +++ b/rfq/oracle.go @@ -8,10 +8,11 @@ import ( "time" "github.com/btcsuite/btcd/btcec/v2" - "github.com/btcsuite/btcd/btcutil" "github.com/lightninglabs/taproot-assets/asset" + "github.com/lightninglabs/taproot-assets/fn" + "github.com/lightninglabs/taproot-assets/rfqmath" + "github.com/lightninglabs/taproot-assets/rfqmsg" oraclerpc "github.com/lightninglabs/taproot-assets/taprpc/priceoraclerpc" - "github.com/lightningnetwork/lnd/lnwire" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" @@ -52,26 +53,15 @@ func (o *OracleError) Error() string { return fmt.Sprintf("OracleError(code=%d, msg=%s)", o.Code, errMsg) } -// OracleAskResponse is a struct that holds the price oracle's suggested ask -// price for an asset. -type OracleAskResponse struct { - // AskPrice is the asking price of the quote. - AskPrice *lnwire.MilliSatoshi +// OracleResponse is a struct that holds the price oracle's suggested buy or +// sell price for an asset swap. +type OracleResponse struct { + // AssetRate is the asset to BTC rate. Other asset in the transfer is + // assumed to be BTC and therefore not included in the response. + AssetRate rfqmath.BigIntFixedPoint - // Expiry is the price expiryDelay lifetime unix timestamp. - Expiry uint64 - - // Err is an optional error returned by the price oracle service. - Err *OracleError -} - -// OracleBidResponse is a struct that holds the price oracle's suggested bid -// price for an asset. -type OracleBidResponse struct { - // BidPrice is the suggested bid price for the asset amount. - BidPrice *lnwire.MilliSatoshi - - // Expiry is the price expiry lifetime unix timestamp in seconds. + // Expiry is the asset to BTC rate expiry lifetime unix timestamp. The + // rate is only valid until this time. Expiry uint64 // Err is an optional error returned by the price oracle service. @@ -121,15 +111,15 @@ type PriceOracle interface { // from another peer to provide the specified asset amount. QueryAskPrice(ctx context.Context, assetId *asset.ID, assetGroupKey *btcec.PublicKey, assetAmount uint64, - suggestedBidPrice *lnwire.MilliSatoshi) (*OracleAskResponse, - error) + assetRateHint fn.Option[rfqmath.BigIntFixedPoint]) ( + *OracleResponse, error) // QueryBidPrice returns the bid price for a given asset amount. // The bid price is the amount the oracle suggests a peer should pay // to another peer to receive the specified asset amount. QueryBidPrice(ctx context.Context, assetId *asset.ID, assetGroupKey *btcec.PublicKey, - assetAmount uint64) (*OracleBidResponse, error) + assetAmount uint64) (*OracleResponse, error) } // RpcPriceOracle is a price oracle that uses an external RPC server to get @@ -214,7 +204,8 @@ func NewRpcPriceOracle(addrStr string, dialInsecure bool) (*RpcPriceOracle, // QueryAskPrice returns the ask price for the given asset amount. func (r *RpcPriceOracle) QueryAskPrice(ctx context.Context, assetId *asset.ID, assetGroupKey *btcec.PublicKey, assetAmount uint64, - bidPrice *lnwire.MilliSatoshi) (*OracleAskResponse, error) { + assetRateHint fn.Option[rfqmath.BigIntFixedPoint]) (*OracleResponse, + error) { // For now, we only support querying the ask price with an asset ID. if assetId == nil { @@ -231,16 +222,40 @@ func (r *RpcPriceOracle) QueryAskPrice(ctx context.Context, copy(subjectAssetId, assetId[:]) // Construct the RPC rate tick hint. - var rateTickHint *oraclerpc.RateTick - if bidPrice != nil { + var ( + rateTickHint *oraclerpc.RateTick + err error + ) + assetRateHint.WhenSome(func(rate rfqmath.BigIntFixedPoint) { // Compute an expiry time using the default expiry delay. expiryTimestamp := uint64(time.Now().Unix()) + defaultRateTickExpirySeconds + // Marshal the subject asset rate. + subjectAssetRate, err := oraclerpc.MarshalBigIntFixedPoint( + rate, + ) + if err != nil { + return + } + + // Marshal the payment asset rate. For now, we only support BTC + // as the payment asset. + paymentAssetRate, err := oraclerpc.MarshalBigIntFixedPoint( + rfqmsg.MilliSatPerBtc, + ) + if err != nil { + return + } + rateTickHint = &oraclerpc.RateTick{ - Rate: uint64(*bidPrice), - ExpiryTimestamp: expiryTimestamp, + SubjectAssetRate: subjectAssetRate, + PaymentAssetRate: paymentAssetRate, + ExpiryTimestamp: expiryTimestamp, } + }) + if err != nil { + return nil, err } req := &oraclerpc.QueryRateTickRequest{ @@ -273,10 +288,17 @@ func (r *RpcPriceOracle) QueryAskPrice(ctx context.Context, "successful but rate tick is nil") } - rate := lnwire.MilliSatoshi(result.Success.RateTick.Rate) - return &OracleAskResponse{ - AskPrice: &rate, - Expiry: result.Success.RateTick.ExpiryTimestamp, + // Unmarshal the subject asset to BTC rate. + rate, err := oraclerpc.UnmarshalFixedPoint( + result.Success.RateTick.SubjectAssetRate, + ) + if err != nil { + return nil, err + } + + return &OracleResponse{ + AssetRate: *rate, + Expiry: result.Success.RateTick.ExpiryTimestamp, }, nil case *oraclerpc.QueryRateTickResponse_Error: @@ -285,7 +307,7 @@ func (r *RpcPriceOracle) QueryAskPrice(ctx context.Context, "an error but error is nil") } - return &OracleAskResponse{ + return &OracleResponse{ Err: &OracleError{ Msg: result.Error.Message, }, @@ -299,7 +321,7 @@ func (r *RpcPriceOracle) QueryAskPrice(ctx context.Context, // QueryBidPrice returns a bid price for the given asset amount. func (r *RpcPriceOracle) QueryBidPrice(ctx context.Context, assetId *asset.ID, assetGroupKey *btcec.PublicKey, - maxAssetAmount uint64) (*OracleBidResponse, error) { + maxAssetAmount uint64) (*OracleResponse, error) { // For now, we only support querying the ask price with an asset ID. if assetId == nil { @@ -345,10 +367,17 @@ func (r *RpcPriceOracle) QueryBidPrice(ctx context.Context, assetId *asset.ID, "successful but rate tick is nil") } - rate := lnwire.MilliSatoshi(result.Success.RateTick.Rate) - return &OracleBidResponse{ - BidPrice: &rate, - Expiry: result.Success.RateTick.ExpiryTimestamp, + // Unmarshal the subject asset to BTC rate. + rate, err := oraclerpc.UnmarshalFixedPoint( + result.Success.RateTick.SubjectAssetRate, + ) + if err != nil { + return nil, err + } + + return &OracleResponse{ + AssetRate: *rate, + Expiry: result.Success.RateTick.ExpiryTimestamp, }, nil case *oraclerpc.QueryRateTickResponse_Error: @@ -357,7 +386,7 @@ func (r *RpcPriceOracle) QueryBidPrice(ctx context.Context, assetId *asset.ID, "an error but error is nil") } - return &OracleBidResponse{ + return &OracleResponse{ Err: &OracleError{ Msg: result.Error.Message, }, @@ -374,56 +403,61 @@ var _ PriceOracle = (*RpcPriceOracle)(nil) // MockPriceOracle is a mock implementation of the PriceOracle interface. // It returns the suggested rate as the exchange rate. type MockPriceOracle struct { - expiryDelay uint64 - mSatPerAsset lnwire.MilliSatoshi + expiryDelay uint64 + assetToBtcRate rfqmath.BigIntFixedPoint } // NewMockPriceOracle creates a new mock price oracle. -func NewMockPriceOracle(expiryDelay, assetsPerBTC uint64) *MockPriceOracle { - mSatPerAsset := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin) / - lnwire.MilliSatoshi(assetsPerBTC) +func NewMockPriceOracle(expiryDelay, + assetRateCoefficient uint64) *MockPriceOracle { return &MockPriceOracle{ - expiryDelay: expiryDelay, - mSatPerAsset: mSatPerAsset, + expiryDelay: expiryDelay, + assetToBtcRate: rfqmath.NewBigIntFixedPoint( + assetRateCoefficient, 0, + ), } } // NewMockPriceOracleSatPerAsset creates a new mock price oracle with a // specified satoshis per asset rate. +// +// TODO(ffranr): Remove in favour of NewMockPriceOracle. func NewMockPriceOracleSatPerAsset(expiryDelay uint64, - satPerAsset btcutil.Amount) *MockPriceOracle { + assetRateCoefficient uint64) *MockPriceOracle { return &MockPriceOracle{ - expiryDelay: expiryDelay, - mSatPerAsset: lnwire.NewMSatFromSatoshis(satPerAsset), + expiryDelay: expiryDelay, + assetToBtcRate: rfqmath.NewBigIntFixedPoint( + assetRateCoefficient, 0, + ), } } // QueryAskPrice returns the ask price for the given asset amount. func (m *MockPriceOracle) QueryAskPrice(_ context.Context, _ *asset.ID, _ *btcec.PublicKey, _ uint64, - _ *lnwire.MilliSatoshi) (*OracleAskResponse, error) { + _ fn.Option[rfqmath.BigIntFixedPoint]) (*OracleResponse, error) { // Calculate the rate expiryDelay lifetime. expiry := uint64(time.Now().Unix()) + m.expiryDelay - return &OracleAskResponse{ - AskPrice: &m.mSatPerAsset, - Expiry: expiry, + return &OracleResponse{ + AssetRate: m.assetToBtcRate, + Expiry: expiry, }, nil } // QueryBidPrice returns a bid price for the given asset amount. func (m *MockPriceOracle) QueryBidPrice(_ context.Context, _ *asset.ID, - _ *btcec.PublicKey, _ uint64) (*OracleBidResponse, error) { + _ *btcec.PublicKey, _ uint64) (*OracleResponse, error) { // Calculate the rate expiryDelay lifetime. expiry := uint64(time.Now().Unix()) + m.expiryDelay - return &OracleBidResponse{ - BidPrice: &m.mSatPerAsset, - Expiry: expiry, + return &OracleResponse{ + AssetRate: m.assetToBtcRate, + Expiry: expiry, }, nil } diff --git a/rfq/oracle_test.go b/rfq/oracle_test.go index 3f1637798..d5601236e 100644 --- a/rfq/oracle_test.go +++ b/rfq/oracle_test.go @@ -10,7 +10,9 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/lightninglabs/taproot-assets/asset" + "github.com/lightninglabs/taproot-assets/fn" "github.com/lightninglabs/taproot-assets/internal/test" + "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightninglabs/taproot-assets/taprpc/priceoraclerpc" "github.com/lightningnetwork/lnd/lnwire" "github.com/stretchr/testify/require" @@ -39,19 +41,29 @@ func (p *mockRpcPriceOracleServer) QueryRateTick(_ context.Context, // Specify a default rate tick in case a rate tick hint is not provided. expiry := time.Now().Add(5 * time.Minute).Unix() + subjectAssetRate := rfqmath.NewBigIntFixedPoint(testRateTick, 3) + + // Marshal the subject asset rate to a fixed point. + subjectAssetFp, err := priceoraclerpc.MarshalBigIntFixedPoint( + subjectAssetRate, + ) + if err != nil { + return nil, err + } + rateTick := priceoraclerpc.RateTick{ - Rate: testRateTick, - ExpiryTimestamp: uint64(expiry), + SubjectAssetRate: subjectAssetFp, + ExpiryTimestamp: uint64(expiry), } - err := validateRateTickRequest(req) + err = validateRateTickRequest(req) if err != nil { return nil, err } // If a rate tick hint is provided, return it as the rate tick. if req.RateTickHint != nil { - rateTick.Rate = req.RateTickHint.Rate + rateTick.SubjectAssetRate = req.RateTickHint.SubjectAssetRate rateTick.ExpiryTimestamp = req.RateTickHint.ExpiryTimestamp } @@ -139,8 +151,13 @@ func runQueryAskPriceTest(t *testing.T, tc *testCaseQueryAskPrice) { assetAmount := uint64(42) bidPrice := lnwire.MilliSatoshi(tc.suggestedRateTick) + inAssetRate := rfqmath.NewBigIntFixedPoint( + tc.suggestedRateTick, 3, + ) + resp, err := client.QueryAskPrice( - ctx, tc.assetId, tc.assetGroupKey, assetAmount, &bidPrice, + ctx, tc.assetId, tc.assetGroupKey, assetAmount, + fn.Some(inAssetRate), ) // If we expect an error, ensure that it is returned. @@ -153,8 +170,10 @@ func runQueryAskPriceTest(t *testing.T, tc *testCaseQueryAskPrice) { require.NoError(t, err) // The mock server should return the rate tick hint/bid. - require.NotNil(t, resp.AskPrice) - require.Equal(t, uint64(bidPrice), uint64(*resp.AskPrice)) + require.NotNil(t, resp.AssetRate) + require.Equal( + t, uint64(bidPrice), resp.AssetRate.Coefficient.ToUint64(), + ) // Ensure that the expiry timestamp is in the future. responseExpiry := time.Unix(int64(resp.Expiry), 0) @@ -248,8 +267,8 @@ func runQueryBidPriceTest(t *testing.T, tc *testCaseQueryBidPrice) { require.NoError(t, err) // The mock server should return the rate tick hint/ask. - require.NotNil(t, resp.BidPrice) - require.Equal(t, testRateTick, uint64(*resp.BidPrice)) + require.NotNil(t, resp.AssetRate) + require.Equal(t, testRateTick, resp.AssetRate.Coefficient.ToUint64()) // Ensure that the expiry timestamp is in the future. responseExpiry := time.Unix(int64(resp.Expiry), 0) diff --git a/tapcfg/server.go b/tapcfg/server.go index 6e8f65578..10db0e4df 100644 --- a/tapcfg/server.go +++ b/tapcfg/server.go @@ -7,7 +7,6 @@ import ( "encoding/binary" "fmt" - "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btclog" "github.com/lightninglabs/lndclient" tap "github.com/lightninglabs/taproot-assets" @@ -356,9 +355,7 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger, case rfqCfg.MockOracleSatsPerAsset > 0: priceOracle = rfq.NewMockPriceOracleSatPerAsset( - 3600, btcutil.Amount( - rfqCfg.MockOracleSatsPerAsset, - ), + 3600, rfqCfg.MockOracleSatsPerAsset, ) } diff --git a/taprpc/priceoraclerpc/marshal.go b/taprpc/priceoraclerpc/marshal.go index 3ae44b051..1b6b029d6 100644 --- a/taprpc/priceoraclerpc/marshal.go +++ b/taprpc/priceoraclerpc/marshal.go @@ -3,6 +3,10 @@ package priceoraclerpc import ( "bytes" "encoding/hex" + "fmt" + "math/big" + + "github.com/lightninglabs/taproot-assets/rfqmath" ) // IsAssetBtc is a helper function that returns true if the given asset @@ -39,3 +43,29 @@ func IsAssetBtc(assetSpecifier *AssetSpecifier) bool { return isAssetIdZero && !groupKeySet } + +// MarshalBigIntFixedPoint converts a BigIntFixedPoint to an RPC FixedPoint. +func MarshalBigIntFixedPoint(fp rfqmath.BigIntFixedPoint) (*FixedPoint, error) { + return &FixedPoint{ + Coefficient: fp.Coefficient.String(), + Scale: uint32(fp.Scale), + }, nil +} + +// UnmarshalFixedPoint converts an RPC FixedPoint to a BigIntFixedPoint. +func UnmarshalFixedPoint(fp *FixedPoint) (*rfqmath.BigIntFixedPoint, error) { + // Return an error is the scale component of the fixed point is greater + // than the max value of uint8. + if fp.Scale > 255 { + return nil, fmt.Errorf("scale value overflow: %v", fp.Scale) + } + scale := uint8(fp.Scale) + + cBigInt := new(big.Int) + cBigInt.SetString(fp.Coefficient, 10) + + return &rfqmath.BigIntFixedPoint{ + Coefficient: rfqmath.NewBigInt(cBigInt), + Scale: scale, + }, nil +} diff --git a/taprpc/priceoraclerpc/price_oracle.pb.go b/taprpc/priceoraclerpc/price_oracle.pb.go index fea9351be..72bec8a13 100644 --- a/taprpc/priceoraclerpc/price_oracle.pb.go +++ b/taprpc/priceoraclerpc/price_oracle.pb.go @@ -69,6 +69,88 @@ func (TransactionType) EnumDescriptor() ([]byte, []int) { return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{0} } +// FixedPoint is a scaled integer representation of a fractional number. +// +// This type consists of two integer fields: a coefficient and a scale. +// Using this format enables precise and consistent representation of fractional +// numbers while avoiding floating-point data types, which are prone to +// precision errors. +// +// The relationship between the fractional representation and its fixed-point +// representation is expressed as: +// ``` +// V = F_c / (10^F_s) +// ``` +// where: +// +// * `V` is the fractional value. +// +// - `F_c` is the coefficient component of the fixed-point representation. It is +// the scaled-up fractional value represented as an integer. +// +// - `F_s` is the scale component. It is an integer specifying how +// many decimal places `F_c` should be divided by to obtain the fractional +// representation. +type FixedPoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The coefficient is the fractional value scaled-up as an integer. This + // integer is represented as a string as it may be too large to fit in a + // uint64. + Coefficient string `protobuf:"bytes,1,opt,name=coefficient,proto3" json:"coefficient,omitempty"` + // The scale is the component that determines how many decimal places + // the coefficient should be divided by to obtain the fractional value. + Scale uint32 `protobuf:"varint,2,opt,name=scale,proto3" json:"scale,omitempty"` +} + +func (x *FixedPoint) Reset() { + *x = FixedPoint{} + if protoimpl.UnsafeEnabled { + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FixedPoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FixedPoint) ProtoMessage() {} + +func (x *FixedPoint) ProtoReflect() protoreflect.Message { + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FixedPoint.ProtoReflect.Descriptor instead. +func (*FixedPoint) Descriptor() ([]byte, []int) { + return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{0} +} + +func (x *FixedPoint) GetCoefficient() string { + if x != nil { + return x.Coefficient + } + return "" +} + +func (x *FixedPoint) GetScale() uint32 { + if x != nil { + return x.Scale + } + return 0 +} + // RateTick is the internal unit used for asset conversions. A tick is 1/10000th // of a currency unit. It gives us up to 4 decimal places of precision (0.0001 // or 0.01% or 1 bps). As an example, if the BTC/USD rate was $61,234.95, then @@ -83,18 +165,27 @@ type RateTick struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // rate is the exchange rate between the subject asset and the payment - // asset. - Rate uint64 `protobuf:"varint,1,opt,name=rate,proto3" json:"rate,omitempty"` + // subjectAssetRate is the number of subject asset units per BTC represented + // as a fixed-point number. This field is also commonly referred to as the + // subject asset to BTC (conversion) rate. When the subject asset is BTC + // milli-satoshis (msats), this field should be set to 100 billion since + // there are 100 billion msats in a BTC. + SubjectAssetRate *FixedPoint `protobuf:"bytes,1,opt,name=subjectAssetRate,proto3" json:"subjectAssetRate,omitempty"` + // paymentAssetRate is the number of payment asset units per BTC represented + // as a fixed-point number. This field is also commonly referred to as the + // payment asset to BTC (conversion) rate. When the payment asset is BTC + // milli-satoshis (msats), this field should be set to 100 billion since + // there are 100 billion msats in a BTC. + PaymentAssetRate *FixedPoint `protobuf:"bytes,2,opt,name=paymentAssetRate,proto3" json:"paymentAssetRate,omitempty"` // expiry_timestamp is the Unix timestamp in seconds after which the rate // tick is no longer valid. - ExpiryTimestamp uint64 `protobuf:"varint,2,opt,name=expiry_timestamp,json=expiryTimestamp,proto3" json:"expiry_timestamp,omitempty"` + ExpiryTimestamp uint64 `protobuf:"varint,3,opt,name=expiry_timestamp,json=expiryTimestamp,proto3" json:"expiry_timestamp,omitempty"` } func (x *RateTick) Reset() { *x = RateTick{} if protoimpl.UnsafeEnabled { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[0] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -107,7 +198,7 @@ func (x *RateTick) String() string { func (*RateTick) ProtoMessage() {} func (x *RateTick) ProtoReflect() protoreflect.Message { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[0] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -120,14 +211,21 @@ func (x *RateTick) ProtoReflect() protoreflect.Message { // Deprecated: Use RateTick.ProtoReflect.Descriptor instead. func (*RateTick) Descriptor() ([]byte, []int) { - return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{0} + return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{1} } -func (x *RateTick) GetRate() uint64 { +func (x *RateTick) GetSubjectAssetRate() *FixedPoint { if x != nil { - return x.Rate + return x.SubjectAssetRate } - return 0 + return nil +} + +func (x *RateTick) GetPaymentAssetRate() *FixedPoint { + if x != nil { + return x.PaymentAssetRate + } + return nil } func (x *RateTick) GetExpiryTimestamp() uint64 { @@ -156,7 +254,7 @@ type AssetSpecifier struct { func (x *AssetSpecifier) Reset() { *x = AssetSpecifier{} if protoimpl.UnsafeEnabled { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[1] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -169,7 +267,7 @@ func (x *AssetSpecifier) String() string { func (*AssetSpecifier) ProtoMessage() {} func (x *AssetSpecifier) ProtoReflect() protoreflect.Message { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[1] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -182,7 +280,7 @@ func (x *AssetSpecifier) ProtoReflect() protoreflect.Message { // Deprecated: Use AssetSpecifier.ProtoReflect.Descriptor instead. func (*AssetSpecifier) Descriptor() ([]byte, []int) { - return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{1} + return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{2} } func (m *AssetSpecifier) GetId() isAssetSpecifier_Id { @@ -281,7 +379,7 @@ type QueryRateTickRequest struct { func (x *QueryRateTickRequest) Reset() { *x = QueryRateTickRequest{} if protoimpl.UnsafeEnabled { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[2] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -294,7 +392,7 @@ func (x *QueryRateTickRequest) String() string { func (*QueryRateTickRequest) ProtoMessage() {} func (x *QueryRateTickRequest) ProtoReflect() protoreflect.Message { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[2] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -307,7 +405,7 @@ func (x *QueryRateTickRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryRateTickRequest.ProtoReflect.Descriptor instead. func (*QueryRateTickRequest) Descriptor() ([]byte, []int) { - return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{2} + return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{3} } func (x *QueryRateTickRequest) GetTransactionType() TransactionType { @@ -358,7 +456,7 @@ type QueryRateTickSuccessResponse struct { func (x *QueryRateTickSuccessResponse) Reset() { *x = QueryRateTickSuccessResponse{} if protoimpl.UnsafeEnabled { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[3] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -371,7 +469,7 @@ func (x *QueryRateTickSuccessResponse) String() string { func (*QueryRateTickSuccessResponse) ProtoMessage() {} func (x *QueryRateTickSuccessResponse) ProtoReflect() protoreflect.Message { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[3] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -384,7 +482,7 @@ func (x *QueryRateTickSuccessResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryRateTickSuccessResponse.ProtoReflect.Descriptor instead. func (*QueryRateTickSuccessResponse) Descriptor() ([]byte, []int) { - return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{3} + return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{4} } func (x *QueryRateTickSuccessResponse) GetRateTick() *RateTick { @@ -409,7 +507,7 @@ type QueryRateTickErrResponse struct { func (x *QueryRateTickErrResponse) Reset() { *x = QueryRateTickErrResponse{} if protoimpl.UnsafeEnabled { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[4] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -422,7 +520,7 @@ func (x *QueryRateTickErrResponse) String() string { func (*QueryRateTickErrResponse) ProtoMessage() {} func (x *QueryRateTickErrResponse) ProtoReflect() protoreflect.Message { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[4] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -435,7 +533,7 @@ func (x *QueryRateTickErrResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryRateTickErrResponse.ProtoReflect.Descriptor instead. func (*QueryRateTickErrResponse) Descriptor() ([]byte, []int) { - return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{4} + return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{5} } func (x *QueryRateTickErrResponse) GetMessage() string { @@ -468,7 +566,7 @@ type QueryRateTickResponse struct { func (x *QueryRateTickResponse) Reset() { *x = QueryRateTickResponse{} if protoimpl.UnsafeEnabled { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[5] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -481,7 +579,7 @@ func (x *QueryRateTickResponse) String() string { func (*QueryRateTickResponse) ProtoMessage() {} func (x *QueryRateTickResponse) ProtoReflect() protoreflect.Message { - mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[5] + mi := &file_priceoraclerpc_price_oracle_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -494,7 +592,7 @@ func (x *QueryRateTickResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryRateTickResponse.ProtoReflect.Descriptor instead. func (*QueryRateTickResponse) Descriptor() ([]byte, []int) { - return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{5} + return file_priceoraclerpc_price_oracle_proto_rawDescGZIP(), []int{6} } func (m *QueryRateTickResponse) GetResult() isQueryRateTickResponse_Result { @@ -542,79 +640,91 @@ var file_priceoraclerpc_price_oracle_proto_rawDesc = []byte{ 0x0a, 0x21, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, - 0x72, 0x70, 0x63, 0x22, 0x49, 0x0a, 0x08, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x12, - 0x12, 0x0a, 0x04, 0x72, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x72, - 0x61, 0x74, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x65, - 0x78, 0x70, 0x69, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x9c, - 0x01, 0x0a, 0x0e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x12, 0x1b, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x22, - 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x53, - 0x74, 0x72, 0x12, 0x1d, 0x0a, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, - 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, - 0x74, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x4b, 0x65, 0x79, 0x53, 0x74, 0x72, 0x42, 0x04, 0x0a, 0x02, 0x69, 0x64, 0x22, 0xe5, 0x02, - 0x0a, 0x14, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, - 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, - 0x65, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x43, 0x0a, 0x0d, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x73, - 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x69, 0x63, - 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, - 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x37, 0x0a, 0x18, 0x73, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x73, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x43, 0x0a, 0x0d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x73, 0x73, 0x65, - 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, - 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, - 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x3e, 0x0a, 0x0e, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, - 0x63, 0x6b, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, - 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x52, - 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x52, 0x0c, 0x72, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, - 0x6b, 0x48, 0x69, 0x6e, 0x74, 0x22, 0x55, 0x0a, 0x1c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, - 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x09, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, - 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, - 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, - 0x63, 0x6b, 0x52, 0x08, 0x72, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, 0x48, 0x0a, 0x18, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 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, 0xad, 0x01, 0x0a, 0x15, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x48, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, - 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, - 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, - 0x00, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x40, 0x0a, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x69, 0x63, - 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 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, 0x32, 0x6b, 0x0a, 0x0b, 0x50, 0x72, 0x69, 0x63, 0x65, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, - 0x12, 0x5c, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, - 0x6b, 0x12, 0x24, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, - 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, - 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, - 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 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, + 0x72, 0x70, 0x63, 0x22, 0x44, 0x0a, 0x0a, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x65, 0x66, 0x66, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x65, 0x66, 0x66, 0x69, 0x63, 0x69, + 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x05, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x22, 0xc5, 0x01, 0x0a, 0x08, 0x52, 0x61, + 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x46, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, + 0x63, 0x2e, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x73, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x12, 0x46, + 0x0a, 0x10, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, + 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, + 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x22, 0x9c, 0x01, 0x0a, 0x0e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, + 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x5f, 0x73, 0x74, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x73, 0x73, 0x65, 0x74, + 0x49, 0x64, 0x53, 0x74, 0x72, 0x12, 0x1d, 0x0a, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, 0x65, + 0x79, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x53, 0x74, 0x72, 0x42, 0x04, 0x0a, 0x02, 0x69, 0x64, + 0x22, 0xe5, 0x02, 0x0a, 0x14, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, + 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x10, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x43, 0x0a, 0x0d, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, + 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, + 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x73, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x37, 0x0a, 0x18, 0x73, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x78, 0x5f, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x73, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x61, 0x78, 0x41, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x12, 0x43, 0x0a, 0x0d, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0c, 0x70, 0x61, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x3e, 0x0a, 0x0e, 0x72, 0x61, 0x74, 0x65, + 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, + 0x63, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x52, 0x0c, 0x72, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x63, 0x6b, 0x48, 0x69, 0x6e, 0x74, 0x22, 0x55, 0x0a, 0x1c, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x09, 0x72, 0x61, 0x74, 0x65, + 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, + 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x74, + 0x65, 0x54, 0x69, 0x63, 0x6b, 0x52, 0x08, 0x72, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, + 0x48, 0x0a, 0x18, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, + 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, 0xad, 0x01, 0x0a, 0x15, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, + 0x69, 0x63, 0x6b, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x48, 0x00, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x40, 0x0a, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, + 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 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, 0x32, 0x6b, 0x0a, 0x0b, 0x50, 0x72, 0x69, 0x63, 0x65, 0x4f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x12, 0x5c, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x63, 0x6b, 0x12, 0x24, 0x2e, 0x70, 0x72, 0x69, 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, + 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, + 0x69, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x52, 0x61, 0x74, 0x65, 0x54, 0x69, 0x63, 0x6b, 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 ( @@ -630,31 +740,34 @@ func file_priceoraclerpc_price_oracle_proto_rawDescGZIP() []byte { } var file_priceoraclerpc_price_oracle_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_priceoraclerpc_price_oracle_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_priceoraclerpc_price_oracle_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_priceoraclerpc_price_oracle_proto_goTypes = []interface{}{ (TransactionType)(0), // 0: priceoraclerpc.TransactionType - (*RateTick)(nil), // 1: priceoraclerpc.RateTick - (*AssetSpecifier)(nil), // 2: priceoraclerpc.AssetSpecifier - (*QueryRateTickRequest)(nil), // 3: priceoraclerpc.QueryRateTickRequest - (*QueryRateTickSuccessResponse)(nil), // 4: priceoraclerpc.QueryRateTickSuccessResponse - (*QueryRateTickErrResponse)(nil), // 5: priceoraclerpc.QueryRateTickErrResponse - (*QueryRateTickResponse)(nil), // 6: priceoraclerpc.QueryRateTickResponse + (*FixedPoint)(nil), // 1: priceoraclerpc.FixedPoint + (*RateTick)(nil), // 2: priceoraclerpc.RateTick + (*AssetSpecifier)(nil), // 3: priceoraclerpc.AssetSpecifier + (*QueryRateTickRequest)(nil), // 4: priceoraclerpc.QueryRateTickRequest + (*QueryRateTickSuccessResponse)(nil), // 5: priceoraclerpc.QueryRateTickSuccessResponse + (*QueryRateTickErrResponse)(nil), // 6: priceoraclerpc.QueryRateTickErrResponse + (*QueryRateTickResponse)(nil), // 7: priceoraclerpc.QueryRateTickResponse } var file_priceoraclerpc_price_oracle_proto_depIdxs = []int32{ - 0, // 0: priceoraclerpc.QueryRateTickRequest.transaction_type:type_name -> priceoraclerpc.TransactionType - 2, // 1: priceoraclerpc.QueryRateTickRequest.subject_asset:type_name -> priceoraclerpc.AssetSpecifier - 2, // 2: priceoraclerpc.QueryRateTickRequest.payment_asset:type_name -> priceoraclerpc.AssetSpecifier - 1, // 3: priceoraclerpc.QueryRateTickRequest.rate_tick_hint:type_name -> priceoraclerpc.RateTick - 1, // 4: priceoraclerpc.QueryRateTickSuccessResponse.rate_tick:type_name -> priceoraclerpc.RateTick - 4, // 5: priceoraclerpc.QueryRateTickResponse.success:type_name -> priceoraclerpc.QueryRateTickSuccessResponse - 5, // 6: priceoraclerpc.QueryRateTickResponse.error:type_name -> priceoraclerpc.QueryRateTickErrResponse - 3, // 7: priceoraclerpc.PriceOracle.QueryRateTick:input_type -> priceoraclerpc.QueryRateTickRequest - 6, // 8: priceoraclerpc.PriceOracle.QueryRateTick:output_type -> priceoraclerpc.QueryRateTickResponse - 8, // [8:9] is the sub-list for method output_type - 7, // [7:8] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 1, // 0: priceoraclerpc.RateTick.subjectAssetRate:type_name -> priceoraclerpc.FixedPoint + 1, // 1: priceoraclerpc.RateTick.paymentAssetRate:type_name -> priceoraclerpc.FixedPoint + 0, // 2: priceoraclerpc.QueryRateTickRequest.transaction_type:type_name -> priceoraclerpc.TransactionType + 3, // 3: priceoraclerpc.QueryRateTickRequest.subject_asset:type_name -> priceoraclerpc.AssetSpecifier + 3, // 4: priceoraclerpc.QueryRateTickRequest.payment_asset:type_name -> priceoraclerpc.AssetSpecifier + 2, // 5: priceoraclerpc.QueryRateTickRequest.rate_tick_hint:type_name -> priceoraclerpc.RateTick + 2, // 6: priceoraclerpc.QueryRateTickSuccessResponse.rate_tick:type_name -> priceoraclerpc.RateTick + 5, // 7: priceoraclerpc.QueryRateTickResponse.success:type_name -> priceoraclerpc.QueryRateTickSuccessResponse + 6, // 8: priceoraclerpc.QueryRateTickResponse.error:type_name -> priceoraclerpc.QueryRateTickErrResponse + 4, // 9: priceoraclerpc.PriceOracle.QueryRateTick:input_type -> priceoraclerpc.QueryRateTickRequest + 7, // 10: priceoraclerpc.PriceOracle.QueryRateTick:output_type -> priceoraclerpc.QueryRateTickResponse + 10, // [10:11] is the sub-list for method output_type + 9, // [9:10] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_priceoraclerpc_price_oracle_proto_init() } @@ -664,7 +777,7 @@ func file_priceoraclerpc_price_oracle_proto_init() { } if !protoimpl.UnsafeEnabled { file_priceoraclerpc_price_oracle_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RateTick); i { + switch v := v.(*FixedPoint); i { case 0: return &v.state case 1: @@ -676,7 +789,7 @@ func file_priceoraclerpc_price_oracle_proto_init() { } } file_priceoraclerpc_price_oracle_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AssetSpecifier); i { + switch v := v.(*RateTick); i { case 0: return &v.state case 1: @@ -688,7 +801,7 @@ func file_priceoraclerpc_price_oracle_proto_init() { } } file_priceoraclerpc_price_oracle_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryRateTickRequest); i { + switch v := v.(*AssetSpecifier); i { case 0: return &v.state case 1: @@ -700,7 +813,7 @@ func file_priceoraclerpc_price_oracle_proto_init() { } } file_priceoraclerpc_price_oracle_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryRateTickSuccessResponse); i { + switch v := v.(*QueryRateTickRequest); i { case 0: return &v.state case 1: @@ -712,7 +825,7 @@ func file_priceoraclerpc_price_oracle_proto_init() { } } file_priceoraclerpc_price_oracle_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryRateTickErrResponse); i { + switch v := v.(*QueryRateTickSuccessResponse); i { case 0: return &v.state case 1: @@ -724,6 +837,18 @@ func file_priceoraclerpc_price_oracle_proto_init() { } } file_priceoraclerpc_price_oracle_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryRateTickErrResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_priceoraclerpc_price_oracle_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*QueryRateTickResponse); i { case 0: return &v.state @@ -736,13 +861,13 @@ func file_priceoraclerpc_price_oracle_proto_init() { } } } - file_priceoraclerpc_price_oracle_proto_msgTypes[1].OneofWrappers = []interface{}{ + file_priceoraclerpc_price_oracle_proto_msgTypes[2].OneofWrappers = []interface{}{ (*AssetSpecifier_AssetId)(nil), (*AssetSpecifier_AssetIdStr)(nil), (*AssetSpecifier_GroupKey)(nil), (*AssetSpecifier_GroupKeyStr)(nil), } - file_priceoraclerpc_price_oracle_proto_msgTypes[5].OneofWrappers = []interface{}{ + file_priceoraclerpc_price_oracle_proto_msgTypes[6].OneofWrappers = []interface{}{ (*QueryRateTickResponse_Success)(nil), (*QueryRateTickResponse_Error)(nil), } @@ -752,7 +877,7 @@ func file_priceoraclerpc_price_oracle_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_priceoraclerpc_price_oracle_proto_rawDesc, NumEnums: 1, - NumMessages: 6, + NumMessages: 7, NumExtensions: 0, NumServices: 1, }, diff --git a/taprpc/priceoraclerpc/price_oracle.proto b/taprpc/priceoraclerpc/price_oracle.proto index c44d2160a..8f09eb99f 100644 --- a/taprpc/priceoraclerpc/price_oracle.proto +++ b/taprpc/priceoraclerpc/price_oracle.proto @@ -22,6 +22,39 @@ enum TransactionType { SALE = 1; } +// FixedPoint is a scaled integer representation of a fractional number. +// +// This type consists of two integer fields: a coefficient and a scale. +// Using this format enables precise and consistent representation of fractional +// numbers while avoiding floating-point data types, which are prone to +// precision errors. +// +// The relationship between the fractional representation and its fixed-point +// representation is expressed as: +// ``` +// V = F_c / (10^F_s) +// ``` +// where: +// +// * `V` is the fractional value. +// +// * `F_c` is the coefficient component of the fixed-point representation. It is +// the scaled-up fractional value represented as an integer. +// +// * `F_s` is the scale component. It is an integer specifying how +// many decimal places `F_c` should be divided by to obtain the fractional +// representation. +message FixedPoint { + // The coefficient is the fractional value scaled-up as an integer. This + // integer is represented as a string as it may be too large to fit in a + // uint64. + string coefficient = 1; + + // The scale is the component that determines how many decimal places + // the coefficient should be divided by to obtain the fractional value. + uint32 scale = 2; +} + // RateTick is the internal unit used for asset conversions. A tick is 1/10000th // of a currency unit. It gives us up to 4 decimal places of precision (0.0001 // or 0.01% or 1 bps). As an example, if the BTC/USD rate was $61,234.95, then @@ -32,13 +65,23 @@ enum TransactionType { // NOTE: That if the payment asset is BTC, the rate tick will be given as // milli-satoshi per asset unit. message RateTick { - // rate is the exchange rate between the subject asset and the payment - // asset. - uint64 rate = 1; + // subjectAssetRate is the number of subject asset units per BTC represented + // as a fixed-point number. This field is also commonly referred to as the + // subject asset to BTC (conversion) rate. When the subject asset is BTC + // milli-satoshis (msats), this field should be set to 100 billion since + // there are 100 billion msats in a BTC. + FixedPoint subjectAssetRate = 1; + + // paymentAssetRate is the number of payment asset units per BTC represented + // as a fixed-point number. This field is also commonly referred to as the + // payment asset to BTC (conversion) rate. When the payment asset is BTC + // milli-satoshis (msats), this field should be set to 100 billion since + // there are 100 billion msats in a BTC. + FixedPoint paymentAssetRate = 2; // expiry_timestamp is the Unix timestamp in seconds after which the rate // tick is no longer valid. - uint64 expiry_timestamp = 2; + uint64 expiry_timestamp = 3; } // AssetSpecifier is a union type for specifying an asset by either its asset ID diff --git a/taprpc/priceoraclerpc/price_oracle.swagger.json b/taprpc/priceoraclerpc/price_oracle.swagger.json index c798d233c..802c0b546 100644 --- a/taprpc/priceoraclerpc/price_oracle.swagger.json +++ b/taprpc/priceoraclerpc/price_oracle.swagger.json @@ -116,12 +116,34 @@ "type": "string" }, { - "name": "rate_tick_hint.rate", - "description": "rate is the exchange rate between the subject asset and the payment\nasset.", + "name": "rate_tick_hint.subjectAssetRate.coefficient", + "description": "The coefficient is the fractional value scaled-up as an integer. This\ninteger is represented as a string as it may be too large to fit in a\nuint64.", "in": "query", "required": false, - "type": "string", - "format": "uint64" + "type": "string" + }, + { + "name": "rate_tick_hint.subjectAssetRate.scale", + "description": "The scale is the component that determines how many decimal places\nthe coefficient should be divided by to obtain the fractional value.", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" + }, + { + "name": "rate_tick_hint.paymentAssetRate.coefficient", + "description": "The coefficient is the fractional value scaled-up as an integer. This\ninteger is represented as a string as it may be too large to fit in a\nuint64.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "rate_tick_hint.paymentAssetRate.scale", + "description": "The scale is the component that determines how many decimal places\nthe coefficient should be divided by to obtain the fractional value.", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" }, { "name": "rate_tick_hint.expiry_timestamp", @@ -163,6 +185,21 @@ }, "description": "AssetSpecifier is a union type for specifying an asset by either its asset ID\nor group key." }, + "priceoraclerpcFixedPoint": { + "type": "object", + "properties": { + "coefficient": { + "type": "string", + "description": "The coefficient is the fractional value scaled-up as an integer. This\ninteger is represented as a string as it may be too large to fit in a\nuint64." + }, + "scale": { + "type": "integer", + "format": "int64", + "description": "The scale is the component that determines how many decimal places\nthe coefficient should be divided by to obtain the fractional value." + } + }, + "description": "FixedPoint is a scaled integer representation of a fractional number.\n\nThis type consists of two integer fields: a coefficient and a scale.\nUsing this format enables precise and consistent representation of fractional\nnumbers while avoiding floating-point data types, which are prone to\nprecision errors.\n\nThe relationship between the fractional representation and its fixed-point\nrepresentation is expressed as:\n```\nV = F_c / (10^F_s)\n```\nwhere:\n\n* `V` is the fractional value.\n\n* `F_c` is the coefficient component of the fixed-point representation. It is\n the scaled-up fractional value represented as an integer.\n\n* `F_s` is the scale component. It is an integer specifying how\n many decimal places `F_c` should be divided by to obtain the fractional\n representation." + }, "priceoraclerpcQueryRateTickErrResponse": { "type": "object", "properties": { @@ -205,10 +242,13 @@ "priceoraclerpcRateTick": { "type": "object", "properties": { - "rate": { - "type": "string", - "format": "uint64", - "description": "rate is the exchange rate between the subject asset and the payment\nasset." + "subjectAssetRate": { + "$ref": "#/definitions/priceoraclerpcFixedPoint", + "description": "subjectAssetRate is the number of subject asset units per BTC represented\nas a fixed-point number. This field is also commonly referred to as the\nsubject asset to BTC (conversion) rate. When the subject asset is BTC\nmilli-satoshis (msats), this field should be set to 100 billion since\nthere are 100 billion msats in a BTC." + }, + "paymentAssetRate": { + "$ref": "#/definitions/priceoraclerpcFixedPoint", + "description": "paymentAssetRate is the number of payment asset units per BTC represented\nas a fixed-point number. This field is also commonly referred to as the\npayment asset to BTC (conversion) rate. When the payment asset is BTC\nmilli-satoshis (msats), this field should be set to 100 billion since\nthere are 100 billion msats in a BTC." }, "expiry_timestamp": { "type": "string", From 6aee68b9424123fb2e0928d0573db67858d4dd1a Mon Sep 17 00:00:00 2001 From: ffranr Date: Tue, 24 Sep 2024 12:54:48 +0100 Subject: [PATCH 05/14] rfq+rfqmsg: replace BuyRequest.BipPrice with SuggestedAssetRate This commit replaces the BuyRequest.BipPrice field with SuggestedAssetRate, changing a `uint64` price to an asset-to-BTC rate represented as a fixed-point number. --- rfq/negotiator.go | 28 ++++------------------ rfqmsg/buy_request.go | 56 +++++++++++++++++++++++++------------------ rfqmsg/request.go | 8 ++++--- 3 files changed, 43 insertions(+), 49 deletions(-) diff --git a/rfq/negotiator.go b/rfq/negotiator.go index 98af38acd..d2deae277 100644 --- a/rfq/negotiator.go +++ b/rfq/negotiator.go @@ -162,12 +162,11 @@ func (n *Negotiator) HandleOutgoingBuyOrder(buyOrder BuyOrder) error { // We calculate a proposed bid price for our peer's // consideration. If a price oracle is not specified we will // skip this step. - var bidPrice lnwire.MilliSatoshi + var assetRateBid fn.Option[rfqmath.BigIntFixedPoint] if n.cfg.PriceOracle != nil { // Query the price oracle for a bid price. - var err error - assetRate, _, err := n.queryBidFromPriceOracle( + rate, _, err := n.queryBidFromPriceOracle( *buyOrder.Peer, buyOrder.AssetID, buyOrder.AssetGroupKey, buyOrder.MinAssetAmount, ) @@ -180,18 +179,13 @@ func (n *Negotiator) HandleOutgoingBuyOrder(buyOrder BuyOrder) error { "request: %v", err) } - // 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(), - ) + assetRateBid = fn.Some[rfqmath.BigIntFixedPoint](*rate) } request, err := rfqmsg.NewBuyRequest( *buyOrder.Peer, buyOrder.AssetID, buyOrder.AssetGroupKey, buyOrder.MinAssetAmount, - bidPrice, + assetRateBid, ) if err != nil { err := fmt.Errorf("unable to create buy request "+ @@ -316,22 +310,10 @@ func (n *Negotiator) HandleIncomingBuyRequest( go func() { defer n.Wg.Done() - // 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. - var suggestedAssetRate fn.Option[rfqmath.BigIntFixedPoint] - if request.BidPrice > 0 { - suggestedAssetRate = fn.Some( - rfqmath.NewBigIntFixedPoint( - uint64(request.BidPrice), 0, - ), - ) - } - // Query the price oracle for an asking price. assetRate, rateExpiry, err := n.queryAskFromPriceOracle( nil, request.AssetID, request.AssetGroupKey, - request.AssetAmount, suggestedAssetRate, + request.AssetAmount, request.SuggestedAssetRate, ) if err != nil { // Send a reject message to the peer. diff --git a/rfqmsg/buy_request.go b/rfqmsg/buy_request.go index 30b34d633..6feec5ab3 100644 --- a/rfqmsg/buy_request.go +++ b/rfqmsg/buy_request.go @@ -6,7 +6,8 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/lightninglabs/taproot-assets/asset" - "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightninglabs/taproot-assets/fn" + "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/tlv" ) @@ -40,14 +41,18 @@ type BuyRequest struct { // requesting a quote. AssetAmount uint64 - // BidPrice is the peer's proposed bid price for the asset amount. - BidPrice lnwire.MilliSatoshi + // SuggestedAssetRate represents a proposed conversion rate between the + // subject asset and BTC. This rate is an initial suggestion intended to + // initiate the RFQ negotiation process and may differ from the final + // agreed rate. + SuggestedAssetRate fn.Option[rfqmath.BigIntFixedPoint] } // NewBuyRequest creates a new asset buy quote request. func NewBuyRequest(peer route.Vertex, assetID *asset.ID, assetGroupKey *btcec.PublicKey, assetAmount uint64, - bidPrice lnwire.MilliSatoshi) (*BuyRequest, error) { + suggestedAssetRate fn.Option[rfqmath.BigIntFixedPoint]) (*BuyRequest, + error) { var id [32]byte _, err := rand.Read(id[:]) @@ -57,13 +62,13 @@ func NewBuyRequest(peer route.Vertex, assetID *asset.ID, } return &BuyRequest{ - Peer: peer, - Version: latestBuyRequestVersion, - ID: id, - AssetID: assetID, - AssetGroupKey: assetGroupKey, - AssetAmount: assetAmount, - BidPrice: bidPrice, + Peer: peer, + Version: latestBuyRequestVersion, + ID: id, + AssetID: assetID, + AssetGroupKey: assetGroupKey, + AssetAmount: assetAmount, + SuggestedAssetRate: suggestedAssetRate, }, nil } @@ -99,22 +104,26 @@ func NewBuyRequestMsgFromWire(wireMsg WireMessage, "request") } - // Extract the suggested rate tick if provided. - var bidPrice lnwire.MilliSatoshi + // Extract the suggested asset to BTC rate if provided. + // + // TODO(ffranr): Temp solution. + var suggestedAssetRate fn.Option[rfqmath.BigIntFixedPoint] msgData.SuggestedRateTick.WhenSome( func(rate tlv.RecordT[tlv.TlvType4, uint64]) { - bidPrice = lnwire.MilliSatoshi(rate.Val) + r := rfqmath.NewBigIntFixedPoint(rate.Val, 0) + suggestedAssetRate = + fn.Some[rfqmath.BigIntFixedPoint](r) }, ) req := BuyRequest{ - Peer: wireMsg.Peer, - Version: msgData.Version.Val, - ID: msgData.ID.Val, - AssetID: assetID, - AssetGroupKey: assetGroupKey, - AssetAmount: msgData.AssetMaxAmount.Val, - BidPrice: bidPrice, + Peer: wireMsg.Peer, + Version: msgData.Version.Val, + ID: msgData.ID.Val, + AssetID: assetID, + AssetGroupKey: assetGroupKey, + AssetAmount: msgData.AssetMaxAmount.Val, + SuggestedAssetRate: suggestedAssetRate, } // Perform basic sanity checks on the quote request. @@ -186,8 +195,9 @@ func (q *BuyRequest) String() string { } return fmt.Sprintf("BuyRequest(peer=%x, id=%x, asset_id=%s, "+ - "asset_group_key=%x, asset_amount=%d, bid_price=%d)", q.Peer[:], - q.ID[:], q.AssetID, groupKeyBytes, q.AssetAmount, q.BidPrice) + "asset_group_key=%x, asset_amount=%d, "+ + "suggested_asset_rate=%v)", q.Peer[:], q.ID[:], q.AssetID, + groupKeyBytes, q.AssetAmount, q.SuggestedAssetRate) } // Ensure that the message type implements the OutgoingMsg interface. diff --git a/rfqmsg/request.go b/rfqmsg/request.go index 2c26ca14c..edadd8f91 100644 --- a/rfqmsg/request.go +++ b/rfqmsg/request.go @@ -8,6 +8,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/lightninglabs/taproot-assets/asset" + "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightningnetwork/lnd/tlv" ) @@ -113,13 +114,14 @@ func newRequestWireMsgDataFromBuy(q BuyRequest) requestWireMsgData { assetMaxAmount := tlv.NewPrimitiveRecord[tlv.TlvType3](q.AssetAmount) var suggestedRateTick requestSuggestedTickRate - if uint64(q.BidPrice) != 0 { + q.SuggestedAssetRate.WhenSome(func(rate rfqmath.BigIntFixedPoint) { suggestedRateTick = tlv.SomeRecordT[tlv.TlvType4]( + // TODO(ffranr): Temp solution. tlv.NewPrimitiveRecord[tlv.TlvType4]( - uint64(q.BidPrice), + rate.Coefficient.ToUint64(), ), ) - } + }) var inAssetID requestInAssetID if q.AssetID != nil { From 239d03500d06d55748bca0f9b0945f955b285d3d Mon Sep 17 00:00:00 2001 From: ffranr Date: Tue, 24 Sep 2024 13:18:31 +0100 Subject: [PATCH 06/14] multi: replace BuyAccept.AskPrice with AssetRate This commit replaces the BuyAccept.AskPrice field with AssetRate, changing a `uint64` price to an asset-to-BTC rate represented as a fixed-point number. --- rfq/negotiator.go | 27 +++++++------------ rfq/order.go | 9 ++++--- rfqmsg/accept.go | 3 ++- rfqmsg/buy_accept.go | 44 +++++++++++++++---------------- rpcserver.go | 5 ++-- tapchannel/aux_invoice_manager.go | 5 +++- taprpc/marshal.go | 5 ++-- 7 files changed, 50 insertions(+), 48 deletions(-) diff --git a/rfq/negotiator.go b/rfq/negotiator.go index d2deae277..0d1f363e0 100644 --- a/rfq/negotiator.go +++ b/rfq/negotiator.go @@ -3,6 +3,7 @@ package rfq import ( "fmt" "math" + "math/big" "sync" "time" @@ -331,14 +332,8 @@ func (n *Negotiator) HandleIncomingBuyRequest( } // Construct and send a buy 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. - askPrice := assetRate.Coefficient.ToUint64() - msg := rfqmsg.NewBuyAcceptFromRequest( - request, lnwire.MilliSatoshi(askPrice), rateExpiry, + request, *assetRate, rateExpiry, ) sendOutgoingMsg(msg) }() @@ -649,24 +644,22 @@ func (n *Negotiator) HandleIncomingBuyAccept(msg rfqmsg.BuyAccept, 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.AskPrice, 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 tolerance. // We will return without calling the quote accept // callback. log.Debugf("Buy accept price is not within "+ - "acceptable bounds (peer_price=%d, "+ - "oracle_price=%d)", msg.AskPrice, oraclePrice) + "acceptable bounds (ask_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 66fe43afd..d1ab8e52c 100644 --- a/rfq/order.go +++ b/rfq/order.go @@ -102,9 +102,12 @@ func NewAssetSalePolicy(quote rfqmsg.BuyAccept) *AssetSalePolicy { return &AssetSalePolicy{ ID: quote.ID, MaxAssetAmount: quote.Request.AssetAmount, - AskPrice: quote.AskPrice, - expiry: quote.Expiry, - assetID: quote.Request.AssetID, + // TODO(ffranr): Temp solution. + AskPrice: lnwire.MilliSatoshi( + quote.AssetRate.Coefficient.ToUint64(), + ), + expiry: quote.Expiry, + assetID: quote.Request.AssetID, } } diff --git a/rfqmsg/accept.go b/rfqmsg/accept.go index b880eb0b7..be46a45bf 100644 --- a/rfqmsg/accept.go +++ b/rfqmsg/accept.go @@ -66,7 +66,8 @@ func newAcceptWireMsgDataFromBuy(q BuyAccept) acceptWireMsgData { // we set the in-out rate tick instead of the out-in rate tick. inOutRateTick := tlv.SomeRecordT[tlv.TlvType4]( tlv.NewPrimitiveRecord[tlv.TlvType4]( - uint64(q.AskPrice), + // TODO(ffranr): Temp solution. + q.AssetRate.Coefficient.ToUint64(), ), ) diff --git a/rfqmsg/buy_accept.go b/rfqmsg/buy_accept.go index 19e79f176..81df44cec 100644 --- a/rfqmsg/buy_accept.go +++ b/rfqmsg/buy_accept.go @@ -3,7 +3,7 @@ package rfqmsg import ( "fmt" - "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/tlv" ) @@ -30,9 +30,8 @@ type BuyAccept struct { // this response is associated with. ID ID - // AskPrice is the asking price of the quote in milli-satoshis per asset - // unit. - AskPrice lnwire.MilliSatoshi + // AssetRate is the accepted asset to BTC rate. + AssetRate rfqmath.BigIntFixedPoint // Expiry is the asking price expiry lifetime unix timestamp. Expiry uint64 @@ -43,16 +42,16 @@ type BuyAccept struct { // NewBuyAcceptFromRequest creates a new instance of a quote accept message // given a quote request message. -func NewBuyAcceptFromRequest(request BuyRequest, askPrice lnwire.MilliSatoshi, - expiry uint64) *BuyAccept { +func NewBuyAcceptFromRequest(request BuyRequest, + assetRate rfqmath.BigIntFixedPoint, expiry uint64) *BuyAccept { return &BuyAccept{ - Peer: request.Peer, - Request: request, - Version: latestBuyAcceptVersion, - ID: request.ID, - AskPrice: askPrice, - Expiry: expiry, + Peer: request.Peer, + Request: request, + Version: latestBuyAcceptVersion, + ID: request.ID, + AssetRate: assetRate, + Expiry: expiry, } } @@ -70,21 +69,22 @@ func newBuyAcceptFromWireMsg(wireMsg WireMessage, // field (and not the out-in rate tick field) because this is the rate // tick field populated in response to a peer initiated buy quote // request. - var askPrice lnwire.MilliSatoshi + var assetRate rfqmath.BigIntFixedPoint msgData.InOutRateTick.WhenSome( func(rate tlv.RecordT[tlv.TlvType4, uint64]) { - askPrice = lnwire.MilliSatoshi(rate.Val) + // TODO(ffranr): Temp solution. + assetRate = rfqmath.NewBigIntFixedPoint(rate.Val, 0) }, ) return &BuyAccept{ - Peer: wireMsg.Peer, - Request: request, - Version: msgData.Version.Val, - ID: msgData.ID.Val, - Expiry: msgData.Expiry.Val, - sig: msgData.Sig.Val, - AskPrice: askPrice, + Peer: wireMsg.Peer, + Request: request, + Version: msgData.Version.Val, + ID: msgData.ID.Val, + Expiry: msgData.Expiry.Val, + sig: msgData.Sig.Val, + AssetRate: assetRate, }, nil } @@ -132,7 +132,7 @@ func (q *BuyAccept) MsgID() ID { func (q *BuyAccept) String() string { return fmt.Sprintf("BuyAccept(peer=%x, id=%x, ask_price=%d, "+ "expiry=%d, scid=%d)", - q.Peer[:], q.ID[:], q.AskPrice, q.Expiry, q.ShortChannelId()) + 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 6c47fa6e5..1da280874 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6596,8 +6596,9 @@ func marshalPeerAcceptedBuyQuotes( Id: quote.ID[:], Scid: uint64(scid), AssetAmount: quote.Request.AssetAmount, - AskPrice: uint64(quote.AskPrice), - Expiry: quote.Expiry, + // TODO(ffranr): Temp solution. + AskPrice: quote.AssetRate.Coefficient.ToUint64(), + Expiry: quote.Expiry, } rpcQuotes = append(rpcQuotes, rpcQuote) } diff --git a/tapchannel/aux_invoice_manager.go b/tapchannel/aux_invoice_manager.go index 8e4d5475a..50ad8eaab 100644 --- a/tapchannel/aux_invoice_manager.go +++ b/tapchannel/aux_invoice_manager.go @@ -213,7 +213,10 @@ func (s *AuxInvoiceManager) priceFromQuote(rfqID rfqmsg.ID) ( log.Debugf("Found buy quote for ID %x / SCID %d: %#v", rfqID[:], rfqID.Scid(), buyQuote) - return buyQuote.AskPrice, nil + // TODO(ffranr): Temp solution. + return lnwire.MilliSatoshi( + buyQuote.AssetRate.Coefficient.ToUint64(), + ), nil case isSell: log.Debugf("Found sell quote for ID %x / SCID %d: %#v", diff --git a/taprpc/marshal.go b/taprpc/marshal.go index c7198f847..9e660d48a 100644 --- a/taprpc/marshal.go +++ b/taprpc/marshal.go @@ -585,8 +585,9 @@ func MarshalAcceptedBuyQuoteEvent( Id: event.ID[:], Scid: uint64(event.ShortChannelId()), AssetAmount: event.Request.AssetAmount, - AskPrice: uint64(event.AskPrice), - Expiry: event.Expiry, + // TODO(ffranr): Temp solution. + AskPrice: event.AssetRate.Coefficient.ToUint64(), + Expiry: event.Expiry, } } From 7822437f67768eb14a7774aabb2b91b14a5b0bdf Mon Sep 17 00:00:00 2001 From: ffranr Date: Tue, 24 Sep 2024 19:16:13 +0100 Subject: [PATCH 07/14] rpc: switch AddInvoice RPC endpoint to fixed-point pricing This commit changes the PeerAcceptedBuyQuote.AskPrice field from a `uint64` to a fixed-point representation for the asset-to-BTC rate. It also updates the invoice milli-sat calculation to use the newly introduced fixed-point field. --- rpcserver.go | 56 +- taprpc/marshal.go | 20 +- taprpc/rfqrpc/marshal.go | 26 + taprpc/rfqrpc/rfq.pb.go | 793 +++++++++++-------- taprpc/rfqrpc/rfq.proto | 38 +- taprpc/rfqrpc/rfq.swagger.json | 22 +- taprpc/tapchannelrpc/tapchannel.swagger.json | 22 +- 7 files changed, 603 insertions(+), 374 deletions(-) create mode 100644 taprpc/rfqrpc/marshal.go diff --git a/rpcserver.go b/rpcserver.go index 1da280874..446ce17ae 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -32,6 +32,7 @@ import ( "github.com/lightninglabs/taproot-assets/mssmt" "github.com/lightninglabs/taproot-assets/proof" "github.com/lightninglabs/taproot-assets/rfq" + "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightninglabs/taproot-assets/rfqmsg" "github.com/lightninglabs/taproot-assets/rpcperms" "github.com/lightninglabs/taproot-assets/tapchannel" @@ -6584,26 +6585,32 @@ func (r *rpcServer) AddAssetBuyOffer(_ context.Context, // into the RPC form. These are quotes that were requested by our node and have // been accepted by our peers. func marshalPeerAcceptedBuyQuotes( - quotes map[rfq.SerialisedScid]rfqmsg.BuyAccept) []*rfqrpc.PeerAcceptedBuyQuote { + quotes map[rfq.SerialisedScid]rfqmsg.BuyAccept) ( + []*rfqrpc.PeerAcceptedBuyQuote, error) { // Marshal the accepted quotes into the RPC form. rpcQuotes := make( []*rfqrpc.PeerAcceptedBuyQuote, 0, len(quotes), ) for scid, quote := range quotes { + coefficient := quote.AssetRate.Coefficient.String() + rpcAskAssetRate := &rfqrpc.FixedPoint{ + Coefficient: coefficient, + Scale: uint32(quote.AssetRate.Scale), + } + rpcQuote := &rfqrpc.PeerAcceptedBuyQuote{ - Peer: quote.Peer.String(), - Id: quote.ID[:], - Scid: uint64(scid), - AssetAmount: quote.Request.AssetAmount, - // TODO(ffranr): Temp solution. - AskPrice: quote.AssetRate.Coefficient.ToUint64(), - Expiry: quote.Expiry, + Peer: quote.Peer.String(), + Id: quote.ID[:], + Scid: uint64(scid), + AssetAmount: quote.Request.AssetAmount, + AskAssetRate: rpcAskAssetRate, + Expiry: quote.Expiry, } rpcQuotes = append(rpcQuotes, rpcQuote) } - return rpcQuotes + return rpcQuotes, nil } // marshalPeerAcceptedSellQuotes marshals a map of peer accepted asset sell @@ -6640,7 +6647,12 @@ func (r *rpcServer) QueryPeerAcceptedQuotes(_ context.Context, peerAcceptedBuyQuotes := r.cfg.RfqManager.PeerAcceptedBuyQuotes() peerAcceptedSellQuotes := r.cfg.RfqManager.PeerAcceptedSellQuotes() - rpcBuyQuotes := marshalPeerAcceptedBuyQuotes(peerAcceptedBuyQuotes) + rpcBuyQuotes, err := marshalPeerAcceptedBuyQuotes(peerAcceptedBuyQuotes) + if err != nil { + return nil, fmt.Errorf("error marshalling peer accepted buy "+ + "quotes: %w", err) + } + rpcSellQuotes := marshalPeerAcceptedSellQuotes(peerAcceptedSellQuotes) return &rfqrpc.QueryPeerAcceptedQuotesResponse{ @@ -6655,7 +6667,11 @@ func marshallRfqEvent(eventInterface fn.Event) (*rfqrpc.RfqEvent, error) { switch event := eventInterface.(type) { case *rfq.PeerAcceptedBuyQuoteEvent: - acceptedQuote := taprpc.MarshalAcceptedBuyQuoteEvent(event) + acceptedQuote, err := taprpc.MarshalAcceptedBuyQuoteEvent(event) + if err != nil { + return nil, err + } + eventRpc := &rfqrpc.RfqEvent_PeerAcceptedBuyQuote{ PeerAcceptedBuyQuote: &rfqrpc.PeerAcceptedBuyQuoteEvent{ Timestamp: uint64(timestamp), @@ -7136,8 +7152,22 @@ func (r *rpcServer) AddInvoice(ctx context.Context, // Now that we have the accepted quote, we know the amount in Satoshi // that we need to pay. We can now update the invoice with this amount. - mSatPerUnit := acceptedQuote.AskPrice - iReq.ValueMsat = int64(req.AssetAmount * mSatPerUnit) + // + // First, un-marshall the ask asset rate from the accepted quote. + askAssetRate, err := rfqrpc.UnmarshalFixedPoint( + acceptedQuote.AskAssetRate, + ) + if err != nil { + return nil, fmt.Errorf("error unmarshalling ask asset rate: %w", + err) + } + + // Convert the asset amount into a fixed-point. + assetAmount := rfqmath.NewBigIntFixedPoint(req.AssetAmount, 0) + + // Calculate the invoice amount in msat. + valMsat := rfqmath.UnitsToMilliSatoshi(assetAmount, *askAssetRate) + iReq.ValueMsat = int64(valMsat) // The last step is to create a hop hint that includes the fake SCID of // the quote, alongside the channel's routing policy. We need to choose diff --git a/taprpc/marshal.go b/taprpc/marshal.go index 9e660d48a..d3a97e5f9 100644 --- a/taprpc/marshal.go +++ b/taprpc/marshal.go @@ -578,17 +578,20 @@ func MarshalAcceptedSellQuoteEvent( // MarshalAcceptedBuyQuoteEvent marshals a peer accepted buy quote event to // its rpc representation. func MarshalAcceptedBuyQuoteEvent( - event *rfq.PeerAcceptedBuyQuoteEvent) *rfqrpc.PeerAcceptedBuyQuote { + event *rfq.PeerAcceptedBuyQuoteEvent) (*rfqrpc.PeerAcceptedBuyQuote, + error) { return &rfqrpc.PeerAcceptedBuyQuote{ Peer: event.Peer.String(), Id: event.ID[:], Scid: uint64(event.ShortChannelId()), AssetAmount: event.Request.AssetAmount, - // TODO(ffranr): Temp solution. - AskPrice: event.AssetRate.Coefficient.ToUint64(), - Expiry: event.Expiry, - } + AskAssetRate: &rfqrpc.FixedPoint{ + Coefficient: event.AssetRate.Coefficient.String(), + Scale: uint32(event.AssetRate.Scale), + }, + Expiry: event.Expiry, + }, nil } // MarshalInvalidQuoteRespEvent marshals an invalid quote response event to @@ -628,8 +631,13 @@ func NewAddAssetBuyOrderResponse( switch e := event.(type) { case *rfq.PeerAcceptedBuyQuoteEvent: + acceptedQuote, err := MarshalAcceptedBuyQuoteEvent(e) + if err != nil { + return nil, err + } + resp.Response = &rfqrpc.AddAssetBuyOrderResponse_AcceptedQuote{ - AcceptedQuote: MarshalAcceptedBuyQuoteEvent(e), + AcceptedQuote: acceptedQuote, } return resp, nil diff --git a/taprpc/rfqrpc/marshal.go b/taprpc/rfqrpc/marshal.go new file mode 100644 index 000000000..331bb88f7 --- /dev/null +++ b/taprpc/rfqrpc/marshal.go @@ -0,0 +1,26 @@ +package rfqrpc + +import ( + "fmt" + "math/big" + + "github.com/lightninglabs/taproot-assets/rfqmath" +) + +// UnmarshalFixedPoint converts an RPC FixedPoint to a BigIntFixedPoint. +func UnmarshalFixedPoint(fp *FixedPoint) (*rfqmath.BigIntFixedPoint, error) { + // Return an error is the scale component of the fixed point is greater + // than the max value of uint8. + if fp.Scale > 255 { + return nil, fmt.Errorf("scale value overflow: %v", fp.Scale) + } + scale := uint8(fp.Scale) + + cBigInt := new(big.Int) + cBigInt.SetString(fp.Coefficient, 10) + + return &rfqmath.BigIntFixedPoint{ + Coefficient: rfqmath.NewBigInt(cBigInt), + Scale: scale, + }, nil +} diff --git a/taprpc/rfqrpc/rfq.pb.go b/taprpc/rfqrpc/rfq.pb.go index d1075c014..5afef7c2c 100644 --- a/taprpc/rfqrpc/rfq.pb.go +++ b/taprpc/rfqrpc/rfq.pb.go @@ -190,6 +190,88 @@ func (*AssetSpecifier_GroupKey) isAssetSpecifier_Id() {} func (*AssetSpecifier_GroupKeyStr) isAssetSpecifier_Id() {} +// FixedPoint is a scaled integer representation of a fractional number. +// +// This type consists of two integer fields: a coefficient and a scale. +// Using this format enables precise and consistent representation of fractional +// numbers while avoiding floating-point data types, which are prone to +// precision errors. +// +// The relationship between the fractional representation and its fixed-point +// representation is expressed as: +// ``` +// V = F_c / (10^F_s) +// ``` +// where: +// +// * `V` is the fractional value. +// +// - `F_c` is the coefficient component of the fixed-point representation. It is +// the scaled-up fractional value represented as an integer. +// +// - `F_s` is the scale component. It is an integer specifying how +// many decimal places `F_c` should be divided by to obtain the fractional +// representation. +type FixedPoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The coefficient is the fractional value scaled-up as an integer. This + // integer is represented as a string as it may be too large to fit in a + // uint64. + Coefficient string `protobuf:"bytes,1,opt,name=coefficient,proto3" json:"coefficient,omitempty"` + // The scale is the component that determines how many decimal places + // the coefficient should be divided by to obtain the fractional value. + Scale uint32 `protobuf:"varint,2,opt,name=scale,proto3" json:"scale,omitempty"` +} + +func (x *FixedPoint) Reset() { + *x = FixedPoint{} + if protoimpl.UnsafeEnabled { + mi := &file_rfqrpc_rfq_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FixedPoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FixedPoint) ProtoMessage() {} + +func (x *FixedPoint) ProtoReflect() protoreflect.Message { + mi := &file_rfqrpc_rfq_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FixedPoint.ProtoReflect.Descriptor instead. +func (*FixedPoint) Descriptor() ([]byte, []int) { + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{1} +} + +func (x *FixedPoint) GetCoefficient() string { + if x != nil { + return x.Coefficient + } + return "" +} + +func (x *FixedPoint) GetScale() uint32 { + if x != nil { + return x.Scale + } + return 0 +} + type AddAssetBuyOrderRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -214,7 +296,7 @@ type AddAssetBuyOrderRequest struct { func (x *AddAssetBuyOrderRequest) Reset() { *x = AddAssetBuyOrderRequest{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[1] + mi := &file_rfqrpc_rfq_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -227,7 +309,7 @@ func (x *AddAssetBuyOrderRequest) String() string { func (*AddAssetBuyOrderRequest) ProtoMessage() {} func (x *AddAssetBuyOrderRequest) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[1] + mi := &file_rfqrpc_rfq_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -240,7 +322,7 @@ func (x *AddAssetBuyOrderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAssetBuyOrderRequest.ProtoReflect.Descriptor instead. func (*AddAssetBuyOrderRequest) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{1} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{2} } func (x *AddAssetBuyOrderRequest) GetAssetSpecifier() *AssetSpecifier { @@ -301,7 +383,7 @@ type AddAssetBuyOrderResponse struct { func (x *AddAssetBuyOrderResponse) Reset() { *x = AddAssetBuyOrderResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[2] + mi := &file_rfqrpc_rfq_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -314,7 +396,7 @@ func (x *AddAssetBuyOrderResponse) String() string { func (*AddAssetBuyOrderResponse) ProtoMessage() {} func (x *AddAssetBuyOrderResponse) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[2] + mi := &file_rfqrpc_rfq_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -327,7 +409,7 @@ func (x *AddAssetBuyOrderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAssetBuyOrderResponse.ProtoReflect.Descriptor instead. func (*AddAssetBuyOrderResponse) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{2} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{3} } func (m *AddAssetBuyOrderResponse) GetResponse() isAddAssetBuyOrderResponse_Response { @@ -410,7 +492,7 @@ type AddAssetSellOrderRequest struct { func (x *AddAssetSellOrderRequest) Reset() { *x = AddAssetSellOrderRequest{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[3] + mi := &file_rfqrpc_rfq_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -423,7 +505,7 @@ func (x *AddAssetSellOrderRequest) String() string { func (*AddAssetSellOrderRequest) ProtoMessage() {} func (x *AddAssetSellOrderRequest) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[3] + mi := &file_rfqrpc_rfq_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -436,7 +518,7 @@ func (x *AddAssetSellOrderRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAssetSellOrderRequest.ProtoReflect.Descriptor instead. func (*AddAssetSellOrderRequest) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{3} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{4} } func (x *AddAssetSellOrderRequest) GetAssetSpecifier() *AssetSpecifier { @@ -497,7 +579,7 @@ type AddAssetSellOrderResponse struct { func (x *AddAssetSellOrderResponse) Reset() { *x = AddAssetSellOrderResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[4] + mi := &file_rfqrpc_rfq_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -510,7 +592,7 @@ func (x *AddAssetSellOrderResponse) String() string { func (*AddAssetSellOrderResponse) ProtoMessage() {} func (x *AddAssetSellOrderResponse) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[4] + mi := &file_rfqrpc_rfq_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -523,7 +605,7 @@ func (x *AddAssetSellOrderResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAssetSellOrderResponse.ProtoReflect.Descriptor instead. func (*AddAssetSellOrderResponse) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{4} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{5} } func (m *AddAssetSellOrderResponse) GetResponse() isAddAssetSellOrderResponse_Response { @@ -596,7 +678,7 @@ type AddAssetSellOfferRequest struct { func (x *AddAssetSellOfferRequest) Reset() { *x = AddAssetSellOfferRequest{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[5] + mi := &file_rfqrpc_rfq_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -609,7 +691,7 @@ func (x *AddAssetSellOfferRequest) String() string { func (*AddAssetSellOfferRequest) ProtoMessage() {} func (x *AddAssetSellOfferRequest) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[5] + mi := &file_rfqrpc_rfq_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -622,7 +704,7 @@ func (x *AddAssetSellOfferRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAssetSellOfferRequest.ProtoReflect.Descriptor instead. func (*AddAssetSellOfferRequest) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{5} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{6} } func (x *AddAssetSellOfferRequest) GetAssetSpecifier() *AssetSpecifier { @@ -648,7 +730,7 @@ type AddAssetSellOfferResponse struct { func (x *AddAssetSellOfferResponse) Reset() { *x = AddAssetSellOfferResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[6] + mi := &file_rfqrpc_rfq_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -661,7 +743,7 @@ func (x *AddAssetSellOfferResponse) String() string { func (*AddAssetSellOfferResponse) ProtoMessage() {} func (x *AddAssetSellOfferResponse) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[6] + mi := &file_rfqrpc_rfq_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -674,7 +756,7 @@ func (x *AddAssetSellOfferResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAssetSellOfferResponse.ProtoReflect.Descriptor instead. func (*AddAssetSellOfferResponse) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{6} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{7} } type AddAssetBuyOfferRequest struct { @@ -691,7 +773,7 @@ type AddAssetBuyOfferRequest struct { func (x *AddAssetBuyOfferRequest) Reset() { *x = AddAssetBuyOfferRequest{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[7] + mi := &file_rfqrpc_rfq_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -704,7 +786,7 @@ func (x *AddAssetBuyOfferRequest) String() string { func (*AddAssetBuyOfferRequest) ProtoMessage() {} func (x *AddAssetBuyOfferRequest) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[7] + mi := &file_rfqrpc_rfq_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -717,7 +799,7 @@ func (x *AddAssetBuyOfferRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAssetBuyOfferRequest.ProtoReflect.Descriptor instead. func (*AddAssetBuyOfferRequest) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{7} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{8} } func (x *AddAssetBuyOfferRequest) GetAssetSpecifier() *AssetSpecifier { @@ -743,7 +825,7 @@ type AddAssetBuyOfferResponse struct { func (x *AddAssetBuyOfferResponse) Reset() { *x = AddAssetBuyOfferResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[8] + mi := &file_rfqrpc_rfq_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -756,7 +838,7 @@ func (x *AddAssetBuyOfferResponse) String() string { func (*AddAssetBuyOfferResponse) ProtoMessage() {} func (x *AddAssetBuyOfferResponse) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[8] + mi := &file_rfqrpc_rfq_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -769,7 +851,7 @@ func (x *AddAssetBuyOfferResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddAssetBuyOfferResponse.ProtoReflect.Descriptor instead. func (*AddAssetBuyOfferResponse) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{8} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{9} } type QueryPeerAcceptedQuotesRequest struct { @@ -781,7 +863,7 @@ type QueryPeerAcceptedQuotesRequest struct { func (x *QueryPeerAcceptedQuotesRequest) Reset() { *x = QueryPeerAcceptedQuotesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[9] + mi := &file_rfqrpc_rfq_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -794,7 +876,7 @@ func (x *QueryPeerAcceptedQuotesRequest) String() string { func (*QueryPeerAcceptedQuotesRequest) ProtoMessage() {} func (x *QueryPeerAcceptedQuotesRequest) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[9] + mi := &file_rfqrpc_rfq_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -807,7 +889,7 @@ func (x *QueryPeerAcceptedQuotesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryPeerAcceptedQuotesRequest.ProtoReflect.Descriptor instead. func (*QueryPeerAcceptedQuotesRequest) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{9} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{10} } type PeerAcceptedBuyQuote struct { @@ -824,8 +906,9 @@ type PeerAcceptedBuyQuote struct { Scid uint64 `protobuf:"varint,3,opt,name=scid,proto3" json:"scid,omitempty"` // asset_amount is the amount of the subject asset. AssetAmount uint64 `protobuf:"varint,4,opt,name=asset_amount,json=assetAmount,proto3" json:"asset_amount,omitempty"` - // ask_price is the price in milli-satoshi per asset unit. - AskPrice uint64 `protobuf:"varint,5,opt,name=ask_price,json=askPrice,proto3" json:"ask_price,omitempty"` + // ask_asset_rate is the asset to BTC conversion rate represented as a + // fixed-point number. + AskAssetRate *FixedPoint `protobuf:"bytes,5,opt,name=ask_asset_rate,json=askAssetRate,proto3" json:"ask_asset_rate,omitempty"` // The unix timestamp in seconds after which the quote is no longer valid. Expiry uint64 `protobuf:"varint,6,opt,name=expiry,proto3" json:"expiry,omitempty"` } @@ -833,7 +916,7 @@ type PeerAcceptedBuyQuote struct { func (x *PeerAcceptedBuyQuote) Reset() { *x = PeerAcceptedBuyQuote{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[10] + mi := &file_rfqrpc_rfq_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -846,7 +929,7 @@ func (x *PeerAcceptedBuyQuote) String() string { func (*PeerAcceptedBuyQuote) ProtoMessage() {} func (x *PeerAcceptedBuyQuote) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[10] + mi := &file_rfqrpc_rfq_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -859,7 +942,7 @@ func (x *PeerAcceptedBuyQuote) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerAcceptedBuyQuote.ProtoReflect.Descriptor instead. func (*PeerAcceptedBuyQuote) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{10} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{11} } func (x *PeerAcceptedBuyQuote) GetPeer() string { @@ -890,11 +973,11 @@ func (x *PeerAcceptedBuyQuote) GetAssetAmount() uint64 { return 0 } -func (x *PeerAcceptedBuyQuote) GetAskPrice() uint64 { +func (x *PeerAcceptedBuyQuote) GetAskAssetRate() *FixedPoint { if x != nil { - return x.AskPrice + return x.AskAssetRate } - return 0 + return nil } func (x *PeerAcceptedBuyQuote) GetExpiry() uint64 { @@ -927,7 +1010,7 @@ type PeerAcceptedSellQuote struct { func (x *PeerAcceptedSellQuote) Reset() { *x = PeerAcceptedSellQuote{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[11] + mi := &file_rfqrpc_rfq_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -940,7 +1023,7 @@ func (x *PeerAcceptedSellQuote) String() string { func (*PeerAcceptedSellQuote) ProtoMessage() {} func (x *PeerAcceptedSellQuote) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[11] + mi := &file_rfqrpc_rfq_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -953,7 +1036,7 @@ func (x *PeerAcceptedSellQuote) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerAcceptedSellQuote.ProtoReflect.Descriptor instead. func (*PeerAcceptedSellQuote) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{11} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{12} } func (x *PeerAcceptedSellQuote) GetPeer() string { @@ -1016,7 +1099,7 @@ type InvalidQuoteResponse struct { func (x *InvalidQuoteResponse) Reset() { *x = InvalidQuoteResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[12] + mi := &file_rfqrpc_rfq_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1029,7 +1112,7 @@ func (x *InvalidQuoteResponse) String() string { func (*InvalidQuoteResponse) ProtoMessage() {} func (x *InvalidQuoteResponse) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[12] + mi := &file_rfqrpc_rfq_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1042,7 +1125,7 @@ func (x *InvalidQuoteResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use InvalidQuoteResponse.ProtoReflect.Descriptor instead. func (*InvalidQuoteResponse) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{12} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{13} } func (x *InvalidQuoteResponse) GetStatus() QuoteRespStatus { @@ -1086,7 +1169,7 @@ type RejectedQuoteResponse struct { func (x *RejectedQuoteResponse) Reset() { *x = RejectedQuoteResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[13] + mi := &file_rfqrpc_rfq_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1099,7 +1182,7 @@ func (x *RejectedQuoteResponse) String() string { func (*RejectedQuoteResponse) ProtoMessage() {} func (x *RejectedQuoteResponse) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[13] + mi := &file_rfqrpc_rfq_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1112,7 +1195,7 @@ func (x *RejectedQuoteResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RejectedQuoteResponse.ProtoReflect.Descriptor instead. func (*RejectedQuoteResponse) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{13} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{14} } func (x *RejectedQuoteResponse) GetPeer() string { @@ -1159,7 +1242,7 @@ type QueryPeerAcceptedQuotesResponse struct { func (x *QueryPeerAcceptedQuotesResponse) Reset() { *x = QueryPeerAcceptedQuotesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[14] + mi := &file_rfqrpc_rfq_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1172,7 +1255,7 @@ func (x *QueryPeerAcceptedQuotesResponse) String() string { func (*QueryPeerAcceptedQuotesResponse) ProtoMessage() {} func (x *QueryPeerAcceptedQuotesResponse) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[14] + mi := &file_rfqrpc_rfq_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1185,7 +1268,7 @@ func (x *QueryPeerAcceptedQuotesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryPeerAcceptedQuotesResponse.ProtoReflect.Descriptor instead. func (*QueryPeerAcceptedQuotesResponse) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{14} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{15} } func (x *QueryPeerAcceptedQuotesResponse) GetBuyQuotes() []*PeerAcceptedBuyQuote { @@ -1211,7 +1294,7 @@ type SubscribeRfqEventNtfnsRequest struct { func (x *SubscribeRfqEventNtfnsRequest) Reset() { *x = SubscribeRfqEventNtfnsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[15] + mi := &file_rfqrpc_rfq_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1224,7 +1307,7 @@ func (x *SubscribeRfqEventNtfnsRequest) String() string { func (*SubscribeRfqEventNtfnsRequest) ProtoMessage() {} func (x *SubscribeRfqEventNtfnsRequest) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[15] + mi := &file_rfqrpc_rfq_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1237,7 +1320,7 @@ func (x *SubscribeRfqEventNtfnsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubscribeRfqEventNtfnsRequest.ProtoReflect.Descriptor instead. func (*SubscribeRfqEventNtfnsRequest) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{15} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{16} } type PeerAcceptedBuyQuoteEvent struct { @@ -1254,7 +1337,7 @@ type PeerAcceptedBuyQuoteEvent struct { func (x *PeerAcceptedBuyQuoteEvent) Reset() { *x = PeerAcceptedBuyQuoteEvent{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[16] + mi := &file_rfqrpc_rfq_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1267,7 +1350,7 @@ func (x *PeerAcceptedBuyQuoteEvent) String() string { func (*PeerAcceptedBuyQuoteEvent) ProtoMessage() {} func (x *PeerAcceptedBuyQuoteEvent) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[16] + mi := &file_rfqrpc_rfq_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1280,7 +1363,7 @@ func (x *PeerAcceptedBuyQuoteEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerAcceptedBuyQuoteEvent.ProtoReflect.Descriptor instead. func (*PeerAcceptedBuyQuoteEvent) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{16} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{17} } func (x *PeerAcceptedBuyQuoteEvent) GetTimestamp() uint64 { @@ -1311,7 +1394,7 @@ type PeerAcceptedSellQuoteEvent struct { func (x *PeerAcceptedSellQuoteEvent) Reset() { *x = PeerAcceptedSellQuoteEvent{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[17] + mi := &file_rfqrpc_rfq_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1324,7 +1407,7 @@ func (x *PeerAcceptedSellQuoteEvent) String() string { func (*PeerAcceptedSellQuoteEvent) ProtoMessage() {} func (x *PeerAcceptedSellQuoteEvent) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[17] + mi := &file_rfqrpc_rfq_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1337,7 +1420,7 @@ func (x *PeerAcceptedSellQuoteEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use PeerAcceptedSellQuoteEvent.ProtoReflect.Descriptor instead. func (*PeerAcceptedSellQuoteEvent) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{17} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{18} } func (x *PeerAcceptedSellQuoteEvent) GetTimestamp() uint64 { @@ -1369,7 +1452,7 @@ type AcceptHtlcEvent struct { func (x *AcceptHtlcEvent) Reset() { *x = AcceptHtlcEvent{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[18] + mi := &file_rfqrpc_rfq_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1382,7 +1465,7 @@ func (x *AcceptHtlcEvent) String() string { func (*AcceptHtlcEvent) ProtoMessage() {} func (x *AcceptHtlcEvent) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[18] + mi := &file_rfqrpc_rfq_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1395,7 +1478,7 @@ func (x *AcceptHtlcEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use AcceptHtlcEvent.ProtoReflect.Descriptor instead. func (*AcceptHtlcEvent) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{18} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{19} } func (x *AcceptHtlcEvent) GetTimestamp() uint64 { @@ -1428,7 +1511,7 @@ type RfqEvent struct { func (x *RfqEvent) Reset() { *x = RfqEvent{} if protoimpl.UnsafeEnabled { - mi := &file_rfqrpc_rfq_proto_msgTypes[19] + mi := &file_rfqrpc_rfq_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1441,7 +1524,7 @@ func (x *RfqEvent) String() string { func (*RfqEvent) ProtoMessage() {} func (x *RfqEvent) ProtoReflect() protoreflect.Message { - mi := &file_rfqrpc_rfq_proto_msgTypes[19] + mi := &file_rfqrpc_rfq_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1454,7 +1537,7 @@ func (x *RfqEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use RfqEvent.ProtoReflect.Descriptor instead. func (*RfqEvent) Descriptor() ([]byte, []int) { - return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{19} + return file_rfqrpc_rfq_proto_rawDescGZIP(), []int{20} } func (m *RfqEvent) GetEvent() isRfqEvent_Event { @@ -1527,224 +1610,230 @@ var file_rfqrpc_rfq_proto_rawDesc = []byte{ 0x0c, 0x48, 0x00, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, - 0x53, 0x74, 0x72, 0x42, 0x04, 0x0a, 0x02, 0x69, 0x64, 0x22, 0x80, 0x02, 0x0a, 0x17, 0x41, 0x64, - 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x73, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x73, - 0x73, 0x65, 0x74, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0e, 0x6d, 0x69, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x17, 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x06, 0x6d, 0x61, 0x78, 0x42, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, - 0x79, 0x12, 0x20, 0x0a, 0x0c, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, - 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x50, 0x75, 0x62, - 0x4b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x73, - 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x74, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0xfa, 0x01, 0x0a, - 0x18, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, 0x4f, 0x72, 0x64, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0e, 0x61, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x41, - 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x75, 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x48, - 0x00, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, - 0x12, 0x43, 0x0a, 0x0d, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, - 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, - 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x46, 0x0a, 0x0e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x51, - 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0d, - 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x42, 0x0a, 0x0a, - 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x81, 0x02, 0x0a, 0x18, 0x41, 0x64, - 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, - 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, - 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, - 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x61, - 0x73, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x41, 0x73, 0x73, 0x65, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x6e, 0x41, 0x73, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, - 0x70, 0x69, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, - 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0c, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, - 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x50, 0x75, - 0x62, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, - 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x74, - 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0xfc, 0x01, - 0x0a, 0x19, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0e, 0x61, - 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, - 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, - 0x74, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x51, 0x75, - 0x6f, 0x74, 0x65, 0x12, 0x43, 0x0a, 0x0d, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x71, - 0x75, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x66, 0x71, - 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x69, 0x6e, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x46, 0x0a, 0x0e, 0x72, 0x65, 0x6a, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, - 0x00, 0x52, 0x0d, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, - 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x78, 0x0a, 0x18, - 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x66, 0x66, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0f, 0x61, 0x73, 0x73, 0x65, - 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, - 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0e, 0x61, 0x73, 0x73, 0x65, 0x74, - 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, - 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, - 0x78, 0x55, 0x6e, 0x69, 0x74, 0x73, 0x22, 0x1b, 0x0a, 0x19, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, - 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x77, 0x0a, 0x17, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, - 0x75, 0x79, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, + 0x53, 0x74, 0x72, 0x42, 0x04, 0x0a, 0x02, 0x69, 0x64, 0x22, 0x44, 0x0a, 0x0a, 0x46, 0x69, 0x78, + 0x65, 0x64, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x65, 0x66, 0x66, + 0x69, 0x63, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, + 0x65, 0x66, 0x66, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x61, + 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x22, + 0x80, 0x02, 0x0a, 0x17, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, 0x4f, + 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0f, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, + 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0e, 0x61, 0x73, + 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, + 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6d, 0x69, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, + 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x61, 0x78, 0x42, 0x69, 0x64, 0x12, + 0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0c, 0x70, 0x65, 0x65, 0x72, 0x5f, + 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, + 0x65, 0x65, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, + 0x75, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x45, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, + 0x2e, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x75, 0x79, + 0x51, 0x75, 0x6f, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, + 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x43, 0x0a, 0x0d, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x51, 0x75, + 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x69, + 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x46, 0x0a, 0x0e, 0x72, + 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6a, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x51, 0x75, + 0x6f, 0x74, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x81, 0x02, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, + 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0f, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0e, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x28, 0x0a, + 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x6d, 0x69, 0x6e, 0x5f, 0x61, + 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x6e, 0x41, 0x73, 0x6b, + 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0c, 0x70, 0x65, 0x65, 0x72, + 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, + 0x70, 0x65, 0x65, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x73, 0x22, 0xfc, 0x01, 0x0a, 0x19, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, + 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x46, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x71, 0x75, + 0x6f, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x66, 0x71, 0x72, + 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, + 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x43, 0x0a, 0x0d, 0x69, 0x6e, 0x76, + 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, + 0x52, 0x0c, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x46, + 0x0a, 0x0e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, + 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x78, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, + 0x6c, 0x6c, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x69, 0x74, 0x73, 0x22, 0x1a, 0x0a, 0x18, - 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, 0x4f, 0x66, 0x66, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x0a, 0x1e, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, - 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa6, 0x01, 0x0a, 0x14, 0x50, - 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x75, 0x79, 0x51, 0x75, - 0x6f, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x63, 0x69, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x63, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, - 0x73, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0b, 0x61, 0x73, 0x73, 0x65, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, - 0x0a, 0x09, 0x61, 0x73, 0x6b, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x08, 0x61, 0x73, 0x6b, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x65, - 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x79, 0x22, 0xa7, 0x01, 0x0a, 0x15, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, - 0x70, 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x65, 0x65, - 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x63, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x04, 0x73, 0x63, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x61, 0x73, 0x73, - 0x65, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x69, 0x64, 0x5f, - 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x62, 0x69, 0x64, - 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x22, 0x6b, 0x0a, - 0x14, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x51, - 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x22, 0x7f, 0x0a, 0x15, 0x52, 0x65, - 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x9e, 0x01, 0x0a, 0x1f, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, - 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x3b, 0x0a, 0x0a, 0x62, 0x75, 0x79, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, - 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x75, 0x79, 0x51, 0x75, 0x6f, 0x74, - 0x65, 0x52, 0x09, 0x62, 0x75, 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x0b, - 0x73, 0x65, 0x6c, 0x6c, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x41, + 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x69, 0x74, 0x73, 0x22, 0x1b, 0x0a, 0x19, + 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x66, 0x66, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x77, 0x0a, 0x17, 0x41, 0x64, 0x64, + 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x70, + 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x6e, 0x69, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x69, + 0x74, 0x73, 0x22, 0x1a, 0x0a, 0x18, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, + 0x79, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, + 0x0a, 0x1e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x22, 0xc3, 0x01, 0x0a, 0x14, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, + 0x64, 0x42, 0x75, 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x65, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x73, 0x63, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x63, 0x69, + 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x61, 0x73, 0x73, 0x65, 0x74, 0x41, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x0e, 0x61, 0x73, 0x6b, 0x5f, 0x61, 0x73, 0x73, 0x65, + 0x74, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x72, + 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x69, 0x78, 0x65, 0x64, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x52, 0x0c, 0x61, 0x73, 0x6b, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, + 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x22, 0xa7, 0x01, 0x0a, 0x15, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, 0x74, 0x65, - 0x52, 0x0a, 0x73, 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x22, 0x1f, 0x0a, 0x1d, - 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x66, 0x71, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8e, 0x01, - 0x0a, 0x19, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x75, - 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x53, 0x0a, 0x17, 0x70, 0x65, 0x65, - 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x79, 0x5f, 0x71, - 0x75, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x66, 0x71, - 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, - 0x42, 0x75, 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x14, 0x70, 0x65, 0x65, 0x72, 0x41, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x75, 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x22, 0x92, - 0x01, 0x0a, 0x1a, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, - 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x56, 0x0a, 0x18, 0x70, - 0x65, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x6c, - 0x6c, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x15, 0x70, 0x65, - 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, 0x51, 0x75, - 0x6f, 0x74, 0x65, 0x22, 0x43, 0x0a, 0x0f, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x48, 0x74, 0x6c, - 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x63, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x04, 0x73, 0x63, 0x69, 0x64, 0x22, 0x8a, 0x02, 0x0a, 0x08, 0x52, 0x66, 0x71, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x5a, 0x0a, 0x17, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x79, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x70, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x63, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x04, 0x73, 0x63, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, + 0x74, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x62, + 0x69, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, + 0x62, 0x69, 0x64, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x69, + 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, + 0x22, 0x6b, 0x0a, 0x14, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, + 0x63, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x65, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x22, 0x7f, 0x0a, + 0x15, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x9e, + 0x01, 0x0a, 0x1f, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x62, 0x75, 0x79, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x75, 0x79, 0x51, - 0x75, 0x6f, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x14, 0x70, 0x65, 0x65, + 0x75, 0x6f, 0x74, 0x65, 0x52, 0x09, 0x62, 0x75, 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x12, + 0x3e, 0x0a, 0x0b, 0x73, 0x65, 0x6c, 0x6c, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, 0x51, 0x75, + 0x6f, 0x74, 0x65, 0x52, 0x0a, 0x73, 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x22, + 0x1f, 0x0a, 0x1d, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x66, 0x71, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x22, 0x8e, 0x01, 0x0a, 0x19, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, + 0x64, 0x42, 0x75, 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x53, 0x0a, 0x17, + 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x75, + 0x79, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x65, 0x64, 0x42, 0x75, 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x14, 0x70, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x75, 0x79, 0x51, 0x75, 0x6f, 0x74, - 0x65, 0x12, 0x5d, 0x0a, 0x18, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, - 0x65, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x6c, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, - 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, - 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x15, 0x70, 0x65, 0x65, 0x72, 0x41, - 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, 0x74, 0x65, - 0x12, 0x3a, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, - 0x63, 0x63, 0x65, 0x70, 0x74, 0x48, 0x74, 0x6c, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, - 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x48, 0x74, 0x6c, 0x63, 0x42, 0x07, 0x0a, 0x05, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2a, 0x58, 0x0a, 0x0f, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x15, 0x0a, 0x11, 0x49, 0x4e, 0x56, 0x41, - 0x4c, 0x49, 0x44, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x49, 0x43, 0x4b, 0x10, 0x00, 0x12, - 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, - 0x59, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x50, 0x52, 0x49, 0x43, 0x45, 0x5f, 0x4f, 0x52, 0x41, - 0x43, 0x4c, 0x45, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x59, 0x5f, 0x45, 0x52, 0x52, 0x10, 0x02, 0x32, - 0xa8, 0x04, 0x0a, 0x03, 0x52, 0x66, 0x71, 0x12, 0x55, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x41, 0x73, - 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x72, 0x66, - 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, - 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x72, - 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, - 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, - 0x0a, 0x11, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, - 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, - 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x41, - 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x12, 0x20, 0x2e, - 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, - 0x65, 0x6c, 0x6c, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x21, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, - 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x55, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, - 0x79, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, - 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, 0x4f, 0x66, 0x66, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, - 0x2e, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, 0x4f, 0x66, 0x66, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x17, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x51, 0x75, - 0x6f, 0x74, 0x65, 0x73, 0x12, 0x26, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x51, - 0x75, 0x6f, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x72, - 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x65, 0x65, 0x72, 0x41, - 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x52, 0x66, 0x71, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x12, - 0x25, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x52, 0x66, 0x71, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, - 0x52, 0x66, 0x71, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x42, 0x37, 0x5a, 0x35, 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, 0x72, 0x66, 0x71, - 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x22, 0x92, 0x01, 0x0a, 0x1a, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x56, + 0x0a, 0x18, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, + 0x73, 0x65, 0x6c, 0x6c, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, + 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, + 0x15, 0x70, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, + 0x6c, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x22, 0x43, 0x0a, 0x0f, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x48, 0x74, 0x6c, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x63, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x63, 0x69, 0x64, 0x22, 0x8a, 0x02, 0x0a, 0x08, + 0x52, 0x66, 0x71, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x5a, 0x0a, 0x17, 0x70, 0x65, 0x65, 0x72, + 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x79, 0x5f, 0x71, 0x75, + 0x6f, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x72, 0x66, 0x71, 0x72, + 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, + 0x75, 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x14, + 0x70, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x75, 0x79, 0x51, + 0x75, 0x6f, 0x74, 0x65, 0x12, 0x5d, 0x0a, 0x18, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x6c, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, + 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, + 0x51, 0x75, 0x6f, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x15, 0x70, 0x65, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x53, 0x65, 0x6c, 0x6c, 0x51, 0x75, + 0x6f, 0x74, 0x65, 0x12, 0x3a, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x68, 0x74, + 0x6c, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, + 0x63, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x48, 0x74, 0x6c, 0x63, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x48, 0x74, 0x6c, 0x63, 0x42, + 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2a, 0x58, 0x0a, 0x0f, 0x51, 0x75, 0x6f, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x15, 0x0a, 0x11, 0x49, + 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x49, 0x43, 0x4b, + 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x45, 0x58, + 0x50, 0x49, 0x52, 0x59, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x50, 0x52, 0x49, 0x43, 0x45, 0x5f, + 0x4f, 0x52, 0x41, 0x43, 0x4c, 0x45, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x59, 0x5f, 0x45, 0x52, 0x52, + 0x10, 0x02, 0x32, 0xa8, 0x04, 0x0a, 0x03, 0x52, 0x66, 0x71, 0x12, 0x55, 0x0a, 0x10, 0x41, 0x64, + 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1f, + 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, + 0x42, 0x75, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x20, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x42, 0x75, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x58, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, + 0x6c, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, + 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x72, 0x64, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, + 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x72, + 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x11, 0x41, + 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x66, 0x66, 0x65, 0x72, + 0x12, 0x20, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x6c, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x10, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x42, 0x75, 0x79, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x72, 0x66, 0x71, 0x72, + 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, 0x4f, 0x66, + 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x72, 0x66, 0x71, + 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x79, 0x4f, + 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x17, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, + 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x12, 0x26, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x65, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x27, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x66, 0x71, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, + 0x6e, 0x73, 0x12, 0x25, 0x2e, 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x66, 0x71, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x72, 0x66, 0x71, 0x72, + 0x70, 0x63, 0x2e, 0x52, 0x66, 0x71, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x42, 0x37, 0x5a, + 0x35, 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, + 0x72, 0x66, 0x71, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1760,66 +1849,68 @@ func file_rfqrpc_rfq_proto_rawDescGZIP() []byte { } var file_rfqrpc_rfq_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_rfqrpc_rfq_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_rfqrpc_rfq_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_rfqrpc_rfq_proto_goTypes = []interface{}{ (QuoteRespStatus)(0), // 0: rfqrpc.QuoteRespStatus (*AssetSpecifier)(nil), // 1: rfqrpc.AssetSpecifier - (*AddAssetBuyOrderRequest)(nil), // 2: rfqrpc.AddAssetBuyOrderRequest - (*AddAssetBuyOrderResponse)(nil), // 3: rfqrpc.AddAssetBuyOrderResponse - (*AddAssetSellOrderRequest)(nil), // 4: rfqrpc.AddAssetSellOrderRequest - (*AddAssetSellOrderResponse)(nil), // 5: rfqrpc.AddAssetSellOrderResponse - (*AddAssetSellOfferRequest)(nil), // 6: rfqrpc.AddAssetSellOfferRequest - (*AddAssetSellOfferResponse)(nil), // 7: rfqrpc.AddAssetSellOfferResponse - (*AddAssetBuyOfferRequest)(nil), // 8: rfqrpc.AddAssetBuyOfferRequest - (*AddAssetBuyOfferResponse)(nil), // 9: rfqrpc.AddAssetBuyOfferResponse - (*QueryPeerAcceptedQuotesRequest)(nil), // 10: rfqrpc.QueryPeerAcceptedQuotesRequest - (*PeerAcceptedBuyQuote)(nil), // 11: rfqrpc.PeerAcceptedBuyQuote - (*PeerAcceptedSellQuote)(nil), // 12: rfqrpc.PeerAcceptedSellQuote - (*InvalidQuoteResponse)(nil), // 13: rfqrpc.InvalidQuoteResponse - (*RejectedQuoteResponse)(nil), // 14: rfqrpc.RejectedQuoteResponse - (*QueryPeerAcceptedQuotesResponse)(nil), // 15: rfqrpc.QueryPeerAcceptedQuotesResponse - (*SubscribeRfqEventNtfnsRequest)(nil), // 16: rfqrpc.SubscribeRfqEventNtfnsRequest - (*PeerAcceptedBuyQuoteEvent)(nil), // 17: rfqrpc.PeerAcceptedBuyQuoteEvent - (*PeerAcceptedSellQuoteEvent)(nil), // 18: rfqrpc.PeerAcceptedSellQuoteEvent - (*AcceptHtlcEvent)(nil), // 19: rfqrpc.AcceptHtlcEvent - (*RfqEvent)(nil), // 20: rfqrpc.RfqEvent + (*FixedPoint)(nil), // 2: rfqrpc.FixedPoint + (*AddAssetBuyOrderRequest)(nil), // 3: rfqrpc.AddAssetBuyOrderRequest + (*AddAssetBuyOrderResponse)(nil), // 4: rfqrpc.AddAssetBuyOrderResponse + (*AddAssetSellOrderRequest)(nil), // 5: rfqrpc.AddAssetSellOrderRequest + (*AddAssetSellOrderResponse)(nil), // 6: rfqrpc.AddAssetSellOrderResponse + (*AddAssetSellOfferRequest)(nil), // 7: rfqrpc.AddAssetSellOfferRequest + (*AddAssetSellOfferResponse)(nil), // 8: rfqrpc.AddAssetSellOfferResponse + (*AddAssetBuyOfferRequest)(nil), // 9: rfqrpc.AddAssetBuyOfferRequest + (*AddAssetBuyOfferResponse)(nil), // 10: rfqrpc.AddAssetBuyOfferResponse + (*QueryPeerAcceptedQuotesRequest)(nil), // 11: rfqrpc.QueryPeerAcceptedQuotesRequest + (*PeerAcceptedBuyQuote)(nil), // 12: rfqrpc.PeerAcceptedBuyQuote + (*PeerAcceptedSellQuote)(nil), // 13: rfqrpc.PeerAcceptedSellQuote + (*InvalidQuoteResponse)(nil), // 14: rfqrpc.InvalidQuoteResponse + (*RejectedQuoteResponse)(nil), // 15: rfqrpc.RejectedQuoteResponse + (*QueryPeerAcceptedQuotesResponse)(nil), // 16: rfqrpc.QueryPeerAcceptedQuotesResponse + (*SubscribeRfqEventNtfnsRequest)(nil), // 17: rfqrpc.SubscribeRfqEventNtfnsRequest + (*PeerAcceptedBuyQuoteEvent)(nil), // 18: rfqrpc.PeerAcceptedBuyQuoteEvent + (*PeerAcceptedSellQuoteEvent)(nil), // 19: rfqrpc.PeerAcceptedSellQuoteEvent + (*AcceptHtlcEvent)(nil), // 20: rfqrpc.AcceptHtlcEvent + (*RfqEvent)(nil), // 21: rfqrpc.RfqEvent } var file_rfqrpc_rfq_proto_depIdxs = []int32{ 1, // 0: rfqrpc.AddAssetBuyOrderRequest.asset_specifier:type_name -> rfqrpc.AssetSpecifier - 11, // 1: rfqrpc.AddAssetBuyOrderResponse.accepted_quote:type_name -> rfqrpc.PeerAcceptedBuyQuote - 13, // 2: rfqrpc.AddAssetBuyOrderResponse.invalid_quote:type_name -> rfqrpc.InvalidQuoteResponse - 14, // 3: rfqrpc.AddAssetBuyOrderResponse.rejected_quote:type_name -> rfqrpc.RejectedQuoteResponse + 12, // 1: rfqrpc.AddAssetBuyOrderResponse.accepted_quote:type_name -> rfqrpc.PeerAcceptedBuyQuote + 14, // 2: rfqrpc.AddAssetBuyOrderResponse.invalid_quote:type_name -> rfqrpc.InvalidQuoteResponse + 15, // 3: rfqrpc.AddAssetBuyOrderResponse.rejected_quote:type_name -> rfqrpc.RejectedQuoteResponse 1, // 4: rfqrpc.AddAssetSellOrderRequest.asset_specifier:type_name -> rfqrpc.AssetSpecifier - 12, // 5: rfqrpc.AddAssetSellOrderResponse.accepted_quote:type_name -> rfqrpc.PeerAcceptedSellQuote - 13, // 6: rfqrpc.AddAssetSellOrderResponse.invalid_quote:type_name -> rfqrpc.InvalidQuoteResponse - 14, // 7: rfqrpc.AddAssetSellOrderResponse.rejected_quote:type_name -> rfqrpc.RejectedQuoteResponse + 13, // 5: rfqrpc.AddAssetSellOrderResponse.accepted_quote:type_name -> rfqrpc.PeerAcceptedSellQuote + 14, // 6: rfqrpc.AddAssetSellOrderResponse.invalid_quote:type_name -> rfqrpc.InvalidQuoteResponse + 15, // 7: rfqrpc.AddAssetSellOrderResponse.rejected_quote:type_name -> rfqrpc.RejectedQuoteResponse 1, // 8: rfqrpc.AddAssetSellOfferRequest.asset_specifier:type_name -> rfqrpc.AssetSpecifier 1, // 9: rfqrpc.AddAssetBuyOfferRequest.asset_specifier:type_name -> rfqrpc.AssetSpecifier - 0, // 10: rfqrpc.InvalidQuoteResponse.status:type_name -> rfqrpc.QuoteRespStatus - 11, // 11: rfqrpc.QueryPeerAcceptedQuotesResponse.buy_quotes:type_name -> rfqrpc.PeerAcceptedBuyQuote - 12, // 12: rfqrpc.QueryPeerAcceptedQuotesResponse.sell_quotes:type_name -> rfqrpc.PeerAcceptedSellQuote - 11, // 13: rfqrpc.PeerAcceptedBuyQuoteEvent.peer_accepted_buy_quote:type_name -> rfqrpc.PeerAcceptedBuyQuote - 12, // 14: rfqrpc.PeerAcceptedSellQuoteEvent.peer_accepted_sell_quote:type_name -> rfqrpc.PeerAcceptedSellQuote - 17, // 15: rfqrpc.RfqEvent.peer_accepted_buy_quote:type_name -> rfqrpc.PeerAcceptedBuyQuoteEvent - 18, // 16: rfqrpc.RfqEvent.peer_accepted_sell_quote:type_name -> rfqrpc.PeerAcceptedSellQuoteEvent - 19, // 17: rfqrpc.RfqEvent.accept_htlc:type_name -> rfqrpc.AcceptHtlcEvent - 2, // 18: rfqrpc.Rfq.AddAssetBuyOrder:input_type -> rfqrpc.AddAssetBuyOrderRequest - 4, // 19: rfqrpc.Rfq.AddAssetSellOrder:input_type -> rfqrpc.AddAssetSellOrderRequest - 6, // 20: rfqrpc.Rfq.AddAssetSellOffer:input_type -> rfqrpc.AddAssetSellOfferRequest - 8, // 21: rfqrpc.Rfq.AddAssetBuyOffer:input_type -> rfqrpc.AddAssetBuyOfferRequest - 10, // 22: rfqrpc.Rfq.QueryPeerAcceptedQuotes:input_type -> rfqrpc.QueryPeerAcceptedQuotesRequest - 16, // 23: rfqrpc.Rfq.SubscribeRfqEventNtfns:input_type -> rfqrpc.SubscribeRfqEventNtfnsRequest - 3, // 24: rfqrpc.Rfq.AddAssetBuyOrder:output_type -> rfqrpc.AddAssetBuyOrderResponse - 5, // 25: rfqrpc.Rfq.AddAssetSellOrder:output_type -> rfqrpc.AddAssetSellOrderResponse - 7, // 26: rfqrpc.Rfq.AddAssetSellOffer:output_type -> rfqrpc.AddAssetSellOfferResponse - 9, // 27: rfqrpc.Rfq.AddAssetBuyOffer:output_type -> rfqrpc.AddAssetBuyOfferResponse - 15, // 28: rfqrpc.Rfq.QueryPeerAcceptedQuotes:output_type -> rfqrpc.QueryPeerAcceptedQuotesResponse - 20, // 29: rfqrpc.Rfq.SubscribeRfqEventNtfns:output_type -> rfqrpc.RfqEvent - 24, // [24:30] is the sub-list for method output_type - 18, // [18:24] is the sub-list for method input_type - 18, // [18:18] is the sub-list for extension type_name - 18, // [18:18] is the sub-list for extension extendee - 0, // [0:18] is the sub-list for field type_name + 2, // 10: rfqrpc.PeerAcceptedBuyQuote.ask_asset_rate:type_name -> rfqrpc.FixedPoint + 0, // 11: rfqrpc.InvalidQuoteResponse.status:type_name -> rfqrpc.QuoteRespStatus + 12, // 12: rfqrpc.QueryPeerAcceptedQuotesResponse.buy_quotes:type_name -> rfqrpc.PeerAcceptedBuyQuote + 13, // 13: rfqrpc.QueryPeerAcceptedQuotesResponse.sell_quotes:type_name -> rfqrpc.PeerAcceptedSellQuote + 12, // 14: rfqrpc.PeerAcceptedBuyQuoteEvent.peer_accepted_buy_quote:type_name -> rfqrpc.PeerAcceptedBuyQuote + 13, // 15: rfqrpc.PeerAcceptedSellQuoteEvent.peer_accepted_sell_quote:type_name -> rfqrpc.PeerAcceptedSellQuote + 18, // 16: rfqrpc.RfqEvent.peer_accepted_buy_quote:type_name -> rfqrpc.PeerAcceptedBuyQuoteEvent + 19, // 17: rfqrpc.RfqEvent.peer_accepted_sell_quote:type_name -> rfqrpc.PeerAcceptedSellQuoteEvent + 20, // 18: rfqrpc.RfqEvent.accept_htlc:type_name -> rfqrpc.AcceptHtlcEvent + 3, // 19: rfqrpc.Rfq.AddAssetBuyOrder:input_type -> rfqrpc.AddAssetBuyOrderRequest + 5, // 20: rfqrpc.Rfq.AddAssetSellOrder:input_type -> rfqrpc.AddAssetSellOrderRequest + 7, // 21: rfqrpc.Rfq.AddAssetSellOffer:input_type -> rfqrpc.AddAssetSellOfferRequest + 9, // 22: rfqrpc.Rfq.AddAssetBuyOffer:input_type -> rfqrpc.AddAssetBuyOfferRequest + 11, // 23: rfqrpc.Rfq.QueryPeerAcceptedQuotes:input_type -> rfqrpc.QueryPeerAcceptedQuotesRequest + 17, // 24: rfqrpc.Rfq.SubscribeRfqEventNtfns:input_type -> rfqrpc.SubscribeRfqEventNtfnsRequest + 4, // 25: rfqrpc.Rfq.AddAssetBuyOrder:output_type -> rfqrpc.AddAssetBuyOrderResponse + 6, // 26: rfqrpc.Rfq.AddAssetSellOrder:output_type -> rfqrpc.AddAssetSellOrderResponse + 8, // 27: rfqrpc.Rfq.AddAssetSellOffer:output_type -> rfqrpc.AddAssetSellOfferResponse + 10, // 28: rfqrpc.Rfq.AddAssetBuyOffer:output_type -> rfqrpc.AddAssetBuyOfferResponse + 16, // 29: rfqrpc.Rfq.QueryPeerAcceptedQuotes:output_type -> rfqrpc.QueryPeerAcceptedQuotesResponse + 21, // 30: rfqrpc.Rfq.SubscribeRfqEventNtfns:output_type -> rfqrpc.RfqEvent + 25, // [25:31] is the sub-list for method output_type + 19, // [19:25] is the sub-list for method input_type + 19, // [19:19] is the sub-list for extension type_name + 19, // [19:19] is the sub-list for extension extendee + 0, // [0:19] is the sub-list for field type_name } func init() { file_rfqrpc_rfq_proto_init() } @@ -1841,7 +1932,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddAssetBuyOrderRequest); i { + switch v := v.(*FixedPoint); i { case 0: return &v.state case 1: @@ -1853,7 +1944,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddAssetBuyOrderResponse); i { + switch v := v.(*AddAssetBuyOrderRequest); i { case 0: return &v.state case 1: @@ -1865,7 +1956,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddAssetSellOrderRequest); i { + switch v := v.(*AddAssetBuyOrderResponse); i { case 0: return &v.state case 1: @@ -1877,7 +1968,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddAssetSellOrderResponse); i { + switch v := v.(*AddAssetSellOrderRequest); i { case 0: return &v.state case 1: @@ -1889,7 +1980,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddAssetSellOfferRequest); i { + switch v := v.(*AddAssetSellOrderResponse); i { case 0: return &v.state case 1: @@ -1901,7 +1992,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddAssetSellOfferResponse); i { + switch v := v.(*AddAssetSellOfferRequest); i { case 0: return &v.state case 1: @@ -1913,7 +2004,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddAssetBuyOfferRequest); i { + switch v := v.(*AddAssetSellOfferResponse); i { case 0: return &v.state case 1: @@ -1925,7 +2016,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddAssetBuyOfferResponse); i { + switch v := v.(*AddAssetBuyOfferRequest); i { case 0: return &v.state case 1: @@ -1937,7 +2028,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryPeerAcceptedQuotesRequest); i { + switch v := v.(*AddAssetBuyOfferResponse); i { case 0: return &v.state case 1: @@ -1949,7 +2040,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PeerAcceptedBuyQuote); i { + switch v := v.(*QueryPeerAcceptedQuotesRequest); i { case 0: return &v.state case 1: @@ -1961,7 +2052,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PeerAcceptedSellQuote); i { + switch v := v.(*PeerAcceptedBuyQuote); i { case 0: return &v.state case 1: @@ -1973,7 +2064,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InvalidQuoteResponse); i { + switch v := v.(*PeerAcceptedSellQuote); i { case 0: return &v.state case 1: @@ -1985,7 +2076,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RejectedQuoteResponse); i { + switch v := v.(*InvalidQuoteResponse); i { case 0: return &v.state case 1: @@ -1997,7 +2088,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryPeerAcceptedQuotesResponse); i { + switch v := v.(*RejectedQuoteResponse); i { case 0: return &v.state case 1: @@ -2009,7 +2100,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubscribeRfqEventNtfnsRequest); i { + switch v := v.(*QueryPeerAcceptedQuotesResponse); i { case 0: return &v.state case 1: @@ -2021,7 +2112,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PeerAcceptedBuyQuoteEvent); i { + switch v := v.(*SubscribeRfqEventNtfnsRequest); i { case 0: return &v.state case 1: @@ -2033,7 +2124,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PeerAcceptedSellQuoteEvent); i { + switch v := v.(*PeerAcceptedBuyQuoteEvent); i { case 0: return &v.state case 1: @@ -2045,7 +2136,7 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AcceptHtlcEvent); i { + switch v := v.(*PeerAcceptedSellQuoteEvent); i { case 0: return &v.state case 1: @@ -2057,6 +2148,18 @@ func file_rfqrpc_rfq_proto_init() { } } file_rfqrpc_rfq_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AcceptHtlcEvent); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rfqrpc_rfq_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RfqEvent); i { case 0: return &v.state @@ -2075,17 +2178,17 @@ func file_rfqrpc_rfq_proto_init() { (*AssetSpecifier_GroupKey)(nil), (*AssetSpecifier_GroupKeyStr)(nil), } - file_rfqrpc_rfq_proto_msgTypes[2].OneofWrappers = []interface{}{ + file_rfqrpc_rfq_proto_msgTypes[3].OneofWrappers = []interface{}{ (*AddAssetBuyOrderResponse_AcceptedQuote)(nil), (*AddAssetBuyOrderResponse_InvalidQuote)(nil), (*AddAssetBuyOrderResponse_RejectedQuote)(nil), } - file_rfqrpc_rfq_proto_msgTypes[4].OneofWrappers = []interface{}{ + file_rfqrpc_rfq_proto_msgTypes[5].OneofWrappers = []interface{}{ (*AddAssetSellOrderResponse_AcceptedQuote)(nil), (*AddAssetSellOrderResponse_InvalidQuote)(nil), (*AddAssetSellOrderResponse_RejectedQuote)(nil), } - file_rfqrpc_rfq_proto_msgTypes[19].OneofWrappers = []interface{}{ + file_rfqrpc_rfq_proto_msgTypes[20].OneofWrappers = []interface{}{ (*RfqEvent_PeerAcceptedBuyQuote)(nil), (*RfqEvent_PeerAcceptedSellQuote)(nil), (*RfqEvent_AcceptHtlc)(nil), @@ -2096,7 +2199,7 @@ func file_rfqrpc_rfq_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rfqrpc_rfq_proto_rawDesc, NumEnums: 1, - NumMessages: 20, + NumMessages: 21, NumExtensions: 0, NumServices: 1, }, diff --git a/taprpc/rfqrpc/rfq.proto b/taprpc/rfqrpc/rfq.proto index e05b554f2..9e536917e 100644 --- a/taprpc/rfqrpc/rfq.proto +++ b/taprpc/rfqrpc/rfq.proto @@ -67,6 +67,39 @@ message AssetSpecifier { } } +// FixedPoint is a scaled integer representation of a fractional number. +// +// This type consists of two integer fields: a coefficient and a scale. +// Using this format enables precise and consistent representation of fractional +// numbers while avoiding floating-point data types, which are prone to +// precision errors. +// +// The relationship between the fractional representation and its fixed-point +// representation is expressed as: +// ``` +// V = F_c / (10^F_s) +// ``` +// where: +// +// * `V` is the fractional value. +// +// * `F_c` is the coefficient component of the fixed-point representation. It is +// the scaled-up fractional value represented as an integer. +// +// * `F_s` is the scale component. It is an integer specifying how +// many decimal places `F_c` should be divided by to obtain the fractional +// representation. +message FixedPoint { + // The coefficient is the fractional value scaled-up as an integer. This + // integer is represented as a string as it may be too large to fit in a + // uint64. + string coefficient = 1; + + // The scale is the component that determines how many decimal places + // the coefficient should be divided by to obtain the fractional value. + uint32 scale = 2; +} + message AddAssetBuyOrderRequest { // asset_specifier is the subject asset. AssetSpecifier asset_specifier = 1; @@ -182,8 +215,9 @@ message PeerAcceptedBuyQuote { // asset_amount is the amount of the subject asset. uint64 asset_amount = 4; - // ask_price is the price in milli-satoshi per asset unit. - uint64 ask_price = 5; + // ask_asset_rate is the asset to BTC conversion rate represented as a + // fixed-point number. + FixedPoint ask_asset_rate = 5; // The unix timestamp in seconds after which the quote is no longer valid. uint64 expiry = 6; diff --git a/taprpc/rfqrpc/rfq.swagger.json b/taprpc/rfqrpc/rfq.swagger.json index 1222a7304..4435446ba 100644 --- a/taprpc/rfqrpc/rfq.swagger.json +++ b/taprpc/rfqrpc/rfq.swagger.json @@ -796,6 +796,21 @@ } } }, + "rfqrpcFixedPoint": { + "type": "object", + "properties": { + "coefficient": { + "type": "string", + "description": "The coefficient is the fractional value scaled-up as an integer. This\ninteger is represented as a string as it may be too large to fit in a\nuint64." + }, + "scale": { + "type": "integer", + "format": "int64", + "description": "The scale is the component that determines how many decimal places\nthe coefficient should be divided by to obtain the fractional value." + } + }, + "description": "FixedPoint is a scaled integer representation of a fractional number.\n\nThis type consists of two integer fields: a coefficient and a scale.\nUsing this format enables precise and consistent representation of fractional\nnumbers while avoiding floating-point data types, which are prone to\nprecision errors.\n\nThe relationship between the fractional representation and its fixed-point\nrepresentation is expressed as:\n```\nV = F_c / (10^F_s)\n```\nwhere:\n\n* `V` is the fractional value.\n\n* `F_c` is the coefficient component of the fixed-point representation. It is\n the scaled-up fractional value represented as an integer.\n\n* `F_s` is the scale component. It is an integer specifying how\n many decimal places `F_c` should be divided by to obtain the fractional\n representation." + }, "rfqrpcInvalidQuoteResponse": { "type": "object", "properties": { @@ -837,10 +852,9 @@ "format": "uint64", "description": "asset_amount is the amount of the subject asset." }, - "ask_price": { - "type": "string", - "format": "uint64", - "description": "ask_price is the price in milli-satoshi per asset unit." + "ask_asset_rate": { + "$ref": "#/definitions/rfqrpcFixedPoint", + "description": "ask_asset_rate is the asset to BTC conversion rate represented as a\nfixed-point number." }, "expiry": { "type": "string", diff --git a/taprpc/tapchannelrpc/tapchannel.swagger.json b/taprpc/tapchannelrpc/tapchannel.swagger.json index b9cd9d6d1..0ff00448a 100644 --- a/taprpc/tapchannelrpc/tapchannel.swagger.json +++ b/taprpc/tapchannelrpc/tapchannel.swagger.json @@ -1042,6 +1042,21 @@ }, "additionalProperties": {} }, + "rfqrpcFixedPoint": { + "type": "object", + "properties": { + "coefficient": { + "type": "string", + "description": "The coefficient is the fractional value scaled-up as an integer. This\ninteger is represented as a string as it may be too large to fit in a\nuint64." + }, + "scale": { + "type": "integer", + "format": "int64", + "description": "The scale is the component that determines how many decimal places\nthe coefficient should be divided by to obtain the fractional value." + } + }, + "description": "FixedPoint is a scaled integer representation of a fractional number.\n\nThis type consists of two integer fields: a coefficient and a scale.\nUsing this format enables precise and consistent representation of fractional\nnumbers while avoiding floating-point data types, which are prone to\nprecision errors.\n\nThe relationship between the fractional representation and its fixed-point\nrepresentation is expressed as:\n```\nV = F_c / (10^F_s)\n```\nwhere:\n\n* `V` is the fractional value.\n\n* `F_c` is the coefficient component of the fixed-point representation. It is\n the scaled-up fractional value represented as an integer.\n\n* `F_s` is the scale component. It is an integer specifying how\n many decimal places `F_c` should be divided by to obtain the fractional\n representation." + }, "rfqrpcPeerAcceptedBuyQuote": { "type": "object", "properties": { @@ -1064,10 +1079,9 @@ "format": "uint64", "description": "asset_amount is the amount of the subject asset." }, - "ask_price": { - "type": "string", - "format": "uint64", - "description": "ask_price is the price in milli-satoshi per asset unit." + "ask_asset_rate": { + "$ref": "#/definitions/rfqrpcFixedPoint", + "description": "ask_asset_rate is the asset to BTC conversion rate represented as a\nfixed-point number." }, "expiry": { "type": "string", From 55923aec9a154ea8d60fc4f2c1f271605a78bdeb Mon Sep 17 00:00:00 2001 From: ffranr Date: Tue, 24 Sep 2024 19:32:41 +0100 Subject: [PATCH 08/14] rfq: add missing doc --- rfq/order.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rfq/order.go b/rfq/order.go index d1ab8e52c..93f936950 100644 --- a/rfq/order.go +++ b/rfq/order.go @@ -79,6 +79,8 @@ type Policy interface { // AssetSalePolicy is a struct that holds the terms which determine whether an // asset sale channel HTLC is accepted or rejected. type AssetSalePolicy struct { + // ID is the unique identifier of the RFQ session that the policy is + // associated with. ID rfqmsg.ID // MaxAssetAmount is the maximum amount of the asset that is being From e90b77de424811f4c8609b22022dedfe4a402476 Mon Sep 17 00:00:00 2001 From: ffranr Date: Thu, 26 Sep 2024 16:59:08 +0100 Subject: [PATCH 09/14] 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 | 33 +++++++++++++++++++++------------ rfqmath/convert.go | 4 ++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/rfq/order.go b/rfq/order.go index 93f936950..c17e92ad2 100644 --- a/rfq/order.go +++ b/rfq/order.go @@ -11,6 +11,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 +88,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 rfqmath.BigIntFixedPoint // expiry is the policy's expiry unix timestamp after which the policy // is no longer valid. @@ -104,12 +104,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 +125,12 @@ func (c *AssetSalePolicy) CheckHtlcCompliance( // Check that the HTLC amount is not greater than the negotiated maximum // amount. - maxOutboundAmount := lnwire.MilliSatoshi(c.MaxAssetAmount) * c.AskPrice + maxAssetAmount := rfqmath.NewBigIntFixedPoint(c.MaxAssetAmount, 0) + + maxOutboundAmount := rfqmath.UnitsToMilliSatoshi( + maxAssetAmount, c.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 +177,15 @@ 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. + outgoingAssetAmount := rfqmath.MilliSatoshiToUnits( + htlc.AmountOutMsat, c.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 21d753d59..c1c246d16 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 { From 23dee0a2f82804785516f21cedf63c7587b70dc7 Mon Sep 17 00:00:00 2001 From: ffranr Date: Mon, 30 Sep 2024 16:17:58 +0100 Subject: [PATCH 10/14] rfq+rfqmsg: replace SellRequest.AskPrice with SuggestedAssetRate This commit replaces the SellRequest.AskPrice field with SuggestedAssetRate, changing a `uint64` price to an asset-to-BTC rate represented as a fixed-point number. --- rfq/negotiator.go | 14 +++-------- rfqmsg/request.go | 7 +++--- rfqmsg/sell_request.go | 57 ++++++++++++++++++++++++------------------ 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/rfq/negotiator.go b/rfq/negotiator.go index 0d1f363e0..f80a0382e 100644 --- a/rfq/negotiator.go +++ b/rfq/negotiator.go @@ -458,12 +458,11 @@ func (n *Negotiator) HandleOutgoingSellOrder(order SellOrder) { // We calculate a proposed ask price for our peer's // consideration. If a price oracle is not specified we will // skip this step. - var askPrice lnwire.MilliSatoshi + var assetRate fn.Option[rfqmath.BigIntFixedPoint] if n.cfg.PriceOracle != nil { // Query the price oracle for an asking price. - var err error - assetRate, _, err := n.queryAskFromPriceOracle( + rate, _, err := n.queryAskFromPriceOracle( order.Peer, order.AssetID, order.AssetGroupKey, order.MaxAssetAmount, fn.None[rfqmath.BigIntFixedPoint](), @@ -475,17 +474,12 @@ func (n *Negotiator) HandleOutgoingSellOrder(order SellOrder) { return } - // 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. - askPrice = lnwire.MilliSatoshi( - assetRate.Coefficient.ToUint64(), - ) + assetRate = fn.Some[rfqmath.BigIntFixedPoint](*rate) } request, err := rfqmsg.NewSellRequest( *order.Peer, order.AssetID, order.AssetGroupKey, - order.MaxAssetAmount, askPrice, + order.MaxAssetAmount, assetRate, ) if err != nil { err := fmt.Errorf("unable to create sell request "+ diff --git a/rfqmsg/request.go b/rfqmsg/request.go index edadd8f91..751c7caaa 100644 --- a/rfqmsg/request.go +++ b/rfqmsg/request.go @@ -176,13 +176,14 @@ func newRequestWireMsgDataFromSell(q SellRequest) requestWireMsgData { assetMaxAmount := tlv.NewPrimitiveRecord[tlv.TlvType3](q.AssetAmount) var suggestedRateTick requestSuggestedTickRate - if uint64(q.AskPrice) != 0 { + q.SuggestedAssetRate.WhenSome(func(rate rfqmath.BigIntFixedPoint) { suggestedRateTick = tlv.SomeRecordT[tlv.TlvType4]( + // TODO(ffranr): Temp solution. tlv.NewPrimitiveRecord[tlv.TlvType4]( - uint64(q.AskPrice), + rate.Coefficient.ToUint64(), ), ) - } + }) // We are constructing a sell request. Therefore, the requesting peer's // outbound asset is the taproot asset, and the inbound asset is BTC. diff --git a/rfqmsg/sell_request.go b/rfqmsg/sell_request.go index a34fc90e7..315c4257a 100644 --- a/rfqmsg/sell_request.go +++ b/rfqmsg/sell_request.go @@ -6,7 +6,8 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/lightninglabs/taproot-assets/asset" - "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightninglabs/taproot-assets/fn" + "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/tlv" ) @@ -40,10 +41,11 @@ type SellRequest struct { // peer intends to sell. AssetAmount uint64 - // AskPrice is the peer's proposed ask price for the asset amount. This - // is not the final price, but a suggested price that the requesting - // peer is willing to accept. - AskPrice lnwire.MilliSatoshi + // SuggestedAssetRate represents a proposed conversion rate between the + // subject asset and BTC. This rate is an initial suggestion intended to + // initiate the RFQ negotiation process and may differ from the final + // agreed rate. + SuggestedAssetRate fn.Option[rfqmath.BigIntFixedPoint] // TODO(ffranr): Add expiry time for suggested ask price. } @@ -51,7 +53,8 @@ type SellRequest struct { // NewSellRequest creates a new asset sell quote request. func NewSellRequest(peer route.Vertex, assetID *asset.ID, assetGroupKey *btcec.PublicKey, assetAmount uint64, - askPrice lnwire.MilliSatoshi) (*SellRequest, error) { + suggestedAssetRate fn.Option[rfqmath.BigIntFixedPoint]) (*SellRequest, + error) { var id [32]byte _, err := rand.Read(id[:]) @@ -60,13 +63,13 @@ func NewSellRequest(peer route.Vertex, assetID *asset.ID, } return &SellRequest{ - Peer: peer, - Version: latestSellRequestVersion, - ID: id, - AssetID: assetID, - AssetGroupKey: assetGroupKey, - AssetAmount: assetAmount, - AskPrice: askPrice, + Peer: peer, + Version: latestSellRequestVersion, + ID: id, + AssetID: assetID, + AssetGroupKey: assetGroupKey, + AssetAmount: assetAmount, + SuggestedAssetRate: suggestedAssetRate, }, nil } @@ -105,22 +108,27 @@ func NewSellRequestMsgFromWire(wireMsg WireMessage, } // Extract the suggested rate tick if provided. - var askPrice lnwire.MilliSatoshi + // + // TODO(ffranr): Temp solution. + var suggestedAssetRate fn.Option[rfqmath.BigIntFixedPoint] msgData.SuggestedRateTick.WhenSome( // nolint: lll func(suggestedRateTick tlv.RecordT[tlv.TlvType4, uint64]) { - askPrice = lnwire.MilliSatoshi(suggestedRateTick.Val) + r := rfqmath.NewBigIntFixedPoint( + suggestedRateTick.Val, 0, + ) + suggestedAssetRate = fn.Some[rfqmath.BigIntFixedPoint](r) }, ) req := SellRequest{ - Peer: wireMsg.Peer, - Version: msgData.Version.Val, - ID: msgData.ID.Val, - AssetID: assetID, - AssetGroupKey: assetGroupKey, - AssetAmount: msgData.AssetMaxAmount.Val, - AskPrice: askPrice, + Peer: wireMsg.Peer, + Version: msgData.Version.Val, + ID: msgData.ID.Val, + AssetID: assetID, + AssetGroupKey: assetGroupKey, + AssetAmount: msgData.AssetMaxAmount.Val, + SuggestedAssetRate: suggestedAssetRate, } // Perform basic sanity checks on the quote request. @@ -192,8 +200,9 @@ func (q *SellRequest) String() string { } return fmt.Sprintf("SellRequest(peer=%x, id=%x, asset_id=%s, "+ - "asset_group_key=%x, asset_amount=%d, ask_price=%d)", q.Peer[:], - q.ID[:], q.AssetID, groupKeyBytes, q.AssetAmount, q.AskPrice) + "asset_group_key=%x, asset_amount=%d, ask_asset_rate=%v)", + q.Peer[:], q.ID[:], q.AssetID, groupKeyBytes, q.AssetAmount, + q.SuggestedAssetRate) } // Ensure that the message type implements the OutgoingMsg interface. From 6458e3b0f09219cf8eb834d846c5f0f148551878 Mon Sep 17 00:00:00 2001 From: ffranr Date: Mon, 30 Sep 2024 16:48:58 +0100 Subject: [PATCH 11/14] 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 | 28 ++++++------------ rfq/order.go | 5 ++-- rfqmsg/accept.go | 3 +- rfqmsg/sell_accept.go | 48 +++++++++++++++---------------- rpcserver.go | 5 ++-- tapchannel/aux_invoice_manager.go | 3 +- tapchannel/aux_traffic_shaper.go | 7 +++-- taprpc/marshal.go | 5 ++-- 8 files changed, 51 insertions(+), 53 deletions(-) diff --git a/rfq/negotiator.go b/rfq/negotiator.go index f80a0382e..456150dbc 100644 --- a/rfq/negotiator.go +++ b/rfq/negotiator.go @@ -427,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) }() @@ -762,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 c17e92ad2..042736847 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..196e44470 100644 --- a/rfqmsg/sell_accept.go +++ b/rfqmsg/sell_accept.go @@ -3,7 +3,7 @@ package rfqmsg import ( "fmt" - "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/tlv" ) @@ -30,9 +30,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 rfqmath.BigIntFixedPoint // Expiry is the bid price expiry lifetime unix timestamp. Expiry uint64 @@ -43,16 +42,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, - expiry uint64) *SellAccept { +func NewSellAcceptFromRequest(request SellRequest, + assetRate rfqmath.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 +71,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 rfqmath.BigIntFixedPoint msgData.OutInRateTick.WhenSome( func(rate tlv.RecordT[tlv.TlvType5, uint64]) { - bidPrice = lnwire.MilliSatoshi(rate.Val) + // TODO(ffranr): Temp solution. + assetRate = rfqmath.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 +135,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 446ce17ae..4d5c938b7 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6627,8 +6627,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 d3a97e5f9..adbee3898 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, } } From 7dbfc2cbee5614a501f731b5d139786f9092a909 Mon Sep 17 00:00:00 2001 From: ffranr Date: Mon, 30 Sep 2024 17:33:32 +0100 Subject: [PATCH 12/14] rfq: remove unused function pricesWithinBounds --- rfq/negotiator.go | 35 ----------- rfq/negotiator_test.go | 136 ----------------------------------------- 2 files changed, 171 deletions(-) delete mode 100644 rfq/negotiator_test.go diff --git a/rfq/negotiator.go b/rfq/negotiator.go index 456150dbc..5bbbbff57 100644 --- a/rfq/negotiator.go +++ b/rfq/negotiator.go @@ -2,7 +2,6 @@ package rfq import ( "fmt" - "math" "math/big" "sync" "time" @@ -13,7 +12,6 @@ import ( "github.com/lightninglabs/taproot-assets/rfqmath" "github.com/lightninglabs/taproot-assets/rfqmsg" "github.com/lightningnetwork/lnd/lnutils" - "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route" ) @@ -507,39 +505,6 @@ func expiryWithinBounds(expiryUnixTimestamp uint64, return diff >= int64(minExpiryLifetime) } -// priceWithinBounds returns true if the difference between the first price and -// the second price is within the given tolerance (in parts per million (PPM)). -// -// TODO(ffranr): Replace with FixedPoint[T].WithinTolerance. -func pricesWithinBounds(firstPrice lnwire.MilliSatoshi, - secondPrice lnwire.MilliSatoshi, tolerancePpm uint64) bool { - - // Handle the case where both prices are zero. - if firstPrice == 0 && secondPrice == 0 { - return true - } - - // Handle cases where either price is zero. - if firstPrice == 0 || secondPrice == 0 { - return false - } - - firstP := float64(firstPrice) - secondP := float64(secondPrice) - - // Calculate the absolute difference between both prices. - delta := math.Abs(firstP - secondP) - - // Normalize the delta by dividing by the greater of the two prices. - normalisedDelta := delta / math.Max(firstP, secondP) - - // Convert the fraction to parts per million (PPM). - deltaPpm := 1_000_000 * normalisedDelta - - // Compare the difference to the tolerance. - return deltaPpm <= float64(tolerancePpm) -} - // HandleIncomingBuyAccept handles an incoming buy accept message. This method // is called when a peer accepts a quote request from this node. The method // checks the price and expiry time of the quote accept message. Once validation diff --git a/rfq/negotiator_test.go b/rfq/negotiator_test.go deleted file mode 100644 index 20e2f1227..000000000 --- a/rfq/negotiator_test.go +++ /dev/null @@ -1,136 +0,0 @@ -package rfq - -import ( - "testing" - - "github.com/lightningnetwork/lnd/lnwire" - "github.com/stretchr/testify/require" -) - -// TestPricesWithinBounds tests the pricesWithinBounds function. -func TestPricesWithinBounds(t *testing.T) { - type testCase struct { - // firstPrice is the price to compare with secondPrice. - firstPrice lnwire.MilliSatoshi - - // secondPrice is the price to compare with firstPrice. - secondPrice lnwire.MilliSatoshi - - // tolerancePpm is the tolerance in parts per million (PPM) that - // the second price can deviate from the first price and still - // be considered within bounds. - tolerancePpm uint64 - - // withinBounds is the expected result of the bounds check. - withinBounds bool - } - - testCases := []testCase{ - { - // Case where secondPrice is 10% less than firstPrice, - // tolerance allows 11.11% (111111 PPM). Diff within - // bounds. - firstPrice: 100000, - secondPrice: 90000, - tolerancePpm: 111111, // 11.11% tolerance in PPM - withinBounds: true, - }, - { - // Case where firstPrice is 15% less than secondPrice, - // tolerance allows 17.65% (176470 PPM). Diff within - // bounds. - firstPrice: 85000, - secondPrice: 100000, - tolerancePpm: 176470, // 17.65% tolerance in PPM - withinBounds: true, - }, - { - // Case where secondPrice is 15% less than firstPrice, - // tolerance allows 10% (100000 PPM). Diff outside - // bounds. - firstPrice: 100000, - secondPrice: 85000, - tolerancePpm: 100000, // 10% tolerance in PPM - withinBounds: false, - }, - { - // Case where firstPrice and secondPrice are equal, - // tolerance is 0 PPM. Diff within bounds. - firstPrice: 100000, - secondPrice: 100000, - tolerancePpm: 0, // 0% tolerance in PPM - withinBounds: true, - }, - { - // Case where secondPrice is 1% more than firstPrice, - // tolerance allows 0.99% (9900 PPM). Diff outside - // bounds. - firstPrice: 100000, - secondPrice: 101000, - tolerancePpm: 9900, // 0.99% tolerance in PPM - withinBounds: false, - }, - { - // Case where secondPrice is 5% less than firstPrice, - // tolerance allows 5% (50000 PPM). Diff within bounds. - firstPrice: 100000, - secondPrice: 95000, - tolerancePpm: 50000, // 5% tolerance in PPM - withinBounds: true, - }, - { - // Case where secondPrice is 10% less than firstPrice, - // tolerance allows 9% (90000 PPM). Diff outside bounds. - firstPrice: 100000, - secondPrice: 90000, - tolerancePpm: 90000, // 9% tolerance in PPM - withinBounds: false, - }, - { - // Case where secondPrice is 9% less than firstPrice, - // tolerance allows 10% (100000 PPM). Diff within - // bounds. - firstPrice: 100000, - secondPrice: 91000, - tolerancePpm: 100000, // 10% tolerance in PPM - withinBounds: true, - }, - { - // Case where both prices are zero, should be within - // bounds. - firstPrice: 0, - secondPrice: 0, - tolerancePpm: 100000, // any tolerance in PPM - withinBounds: true, - }, - { - // Case where firstPrice is zero and secondPrice is - // non-zero, should not be within bounds. - firstPrice: 0, - secondPrice: 100000, - tolerancePpm: 100000, // any tolerance in PPM - withinBounds: false, - }, - { - // Case where secondPrice is zero and firstPrice is - // non-zero, should not be within bounds. - firstPrice: 100000, - secondPrice: 0, - tolerancePpm: 100000, // any tolerance in PPM - withinBounds: false, - }, - } - - // Run the test cases. - for idx, tc := range testCases { - result := pricesWithinBounds( - tc.firstPrice, tc.secondPrice, tc.tolerancePpm, - ) - - // Compare bounds check result with expected test case within - // bounds flag. - require.Equal( - t, tc.withinBounds, result, "Test case %d failed", idx, - ) - } -} From eeeb198eeb3b4cee4be6b4533cf4aa12824ca3e9 Mon Sep 17 00:00:00 2001 From: ffranr Date: Wed, 16 Oct 2024 11:47:50 +0100 Subject: [PATCH 13/14] rfqmath: test for UnitsToMilliSatoshi consistency with decimal display This test ensures that converting an asset amount to fixed-point values with different scales produces the same result when used in `UnitsToMilliSatoshi`. The test confirms that the absence of a decimal display value (scale) does not affect the final result. --- rfqmath/convert_test.go | 78 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/rfqmath/convert_test.go b/rfqmath/convert_test.go index a63686a57..6e1e74e53 100644 --- a/rfqmath/convert_test.go +++ b/rfqmath/convert_test.go @@ -458,6 +458,84 @@ func TestConvertMilliSatoshiToUnits(t *testing.T) { } } +// TestAssetAmtScaleRedundant ensures that the asset amount, when represented +// as a fixed-point value, behaves consistently across different scale factors. +// +// The test validates that converting an asset amount to two different +// fixed-point representations (one with a scale of 0 and one with a random +// non-zero scale) will yield the same result when both are used in the +// `UnitsToMilliSatoshi` function. +// +// Specifically, the test does the following: +// 1. Generates a random `uint64` asset amount and constructs a fixed-point +// representation with a scale of 0. +// 2. Generates a random scale greater than 0 and constructs another +// fixed-point representation of the same asset amount with this non-zero +// scale. +// 3. Validates that the two fixed-point representations yield the same +// result when used with a randomly generated asset unit to BTC rate +// in the `UnitsToMilliSatoshi` function. +// +// The test ensures that despite differences in scale, the conversion to +// milli-satoshis remains equivalent, confirming that the scale factor +// does not introduce inconsistencies. +// +// The test demonstrates that including the decimal display value (as the scale +// value or otherwise) when defining the asset amount has no effect on the +// result calculated using `UnitsToMilliSatoshi`. +func TestAssetAmtScaleRedundant(t *testing.T) { + t.Parallel() + + rapid.Check(t, func(t *rapid.T) { + // Compute the asset amount as a `uint64`. We will convert this + // value to two different FixedPoint values, one with a scale of + // 0 and one with a random scale value greater than 0. + assetAmt := + rapid.Uint64Range(1, 100_000_000).Draw(t, "assetAmt") + + // Construct asset amount fixed-point with a scale value of 0. + // + // Note: We use the `NewBigIntFixedPoint` helper function to + // construct the fixed-point value with a scale of 0. This is + // equivalent to: + // + // assetAmtBigInt := new(big.Int).SetUint64(assetAmt) + // assetAmtZeroScale := FixedPoint[BigInt]{ + // Coefficient: NewBigInt(assetAmtBigInt), + // Scale: uint8(0), + // } + assetAmtZeroScale := NewBigIntFixedPoint(assetAmt, 0) + require.Equal(t, assetAmtZeroScale.Scale, uint8(0)) + + // Construct a second asset amount fixed-point with a random + // scale value which is greater than 0. + assetAmtFpScale := uint8( + rapid.IntRange(2, 9).Draw(t, "assetAmountFpScale"), + ) + assetAmtNonZeroScale := FixedPointFromUint64[BigInt]( + assetAmt, assetAmtFpScale, + ) + require.Greater(t, assetAmtNonZeroScale.Scale, uint8(0)) + + // Ensure that both asset amounts, when used with + // UnitsToMilliSatoshi, yield the same result. + // + // Construct a random asset unit to BTC rate. + assetRate := + rapid.Uint64Range(1, 100_000_000).Draw(t, "assetRate") + scale := uint8(rapid.IntRange(2, 9).Draw(t, "scale")) + assetRateFp := FixedPointFromUint64[BigInt](assetRate, scale) + + // Call UnitsToMilliSatoshi with both asset amount fixed-point + // numbers. + mSat1 := UnitsToMilliSatoshi(assetAmtZeroScale, assetRateFp) + mSat2 := UnitsToMilliSatoshi(assetAmtNonZeroScale, assetRateFp) + + require.Equal(t, mSat1, mSat2) + require.Greater(t, uint64(mSat1), uint64(0)) + }) +} + // TestConvertUsdToJpy tests the conversion of USD to JPY using a BTC price in // USD and a BTC price in JPY, both expressed as a FixedPoint. func TestConvertUsdToJpy(t *testing.T) { From 615fc4d53b255e31233af56b09bee3c603395536 Mon Sep 17 00:00:00 2001 From: ffranr Date: Wed, 16 Oct 2024 20:06:24 +0100 Subject: [PATCH 14/14] rfqmath: add example for price oracle rate and asset conversion to msat Add a unit test demonstrating how a price oracle returns a TAP asset-to-BTC rate and how that rate is used to convert an asset amount into msats. --- rfqmath/convert_test.go | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/rfqmath/convert_test.go b/rfqmath/convert_test.go index 6e1e74e53..390b21635 100644 --- a/rfqmath/convert_test.go +++ b/rfqmath/convert_test.go @@ -458,6 +458,62 @@ func TestConvertMilliSatoshiToUnits(t *testing.T) { } } +// TestPriceOracleRateExample demonstrates how to use the price oracle to +// convert an asset amount to milli-satoshis. +func TestPriceOracleRateExample(t *testing.T) { + // A query is sent to the price oracle for the tap asset to BTC rate for + // a given tap asset. + // + // The price oracle recognizes the asset as a USD stable coin. It looks + // up the current BTC price in USD: 67,918.90 USD/BTC, equivalent to + // 1472 satoshi per USD. This is expressed as a fixed-point with + // coefficient 679_189_000 and scale 2. + centsPerBtcCoefficient := uint64(679_189_000) + centsPerBtc := NewBigIntFixedPoint(centsPerBtcCoefficient, 2) + require.Equal(t, "6791890.00", centsPerBtc.String()) + + // The price oracle doesn't return the cents per BTC rate, instead it + // returns the tap asset units per BTC rate. It does this so that the + // asset to BTC rate in the RFQ wire messages and in all internal tapd + // calculations do not need to be aware of the asset's decimal display. + // + // In order to return the tap asset units per BTC rate, the price oracle + // needs to convert the cents per BTC rate to tap asset units per BTC + // rate. This is accomplished internally by the price oracle by + // constructing a multiplier from the asset's decimal display. + // + // The asset has a decimal display of 2, which means 100 tap asset units + // are equal to one USD cent. + decimalDisplay := 2 + centsToTap := uint64(math.Pow(float64(10), float64(decimalDisplay))) + + // Calculating the asset units per BTC rate is done by multiplying the + // cents per BTC rate by the decimal display multiplier. It is not a + // matter of re-scaling the cents per BTC rate fixed-point. + assetUnitsPerBtc := NewBigIntFixedPoint( + centsPerBtcCoefficient*centsToTap, 2, + ) + require.Equal(t, "679189000.00", assetUnitsPerBtc.String()) + + // Now we'll use the asset units per BTC rate to convert an asset amount + // to milli-satoshis. + // + // The decimal display of the asset is 2, which means 100 units are + // equal to one USD cent. We have an asset amount of 10_000 units, which + // is equal to one USD dollar (100 USD cents). Note that previously we + // said that 67,918.90 USD/BTC is equivalent to 1472 satoshi per USD. + assetAmount := NewBigIntFixedPoint(10_000, 0) + mSat := UnitsToMilliSatoshi(assetAmount, assetUnitsPerBtc) + require.EqualValues(t, 1472, mSat.ToSatoshis()) + + // The asset amount fixed point can have any scale and does not need to + // match the asset's decimal display. This is because the price oracle + // returns an asset units per BTC rate and not a cents per BTC rate. + assetAmount = NewBigIntFixedPoint(10_000_000, 3) + mSat = UnitsToMilliSatoshi(assetAmount, assetUnitsPerBtc) + require.EqualValues(t, 1472, mSat.ToSatoshis()) +} + // TestAssetAmtScaleRedundant ensures that the asset amount, when represented // as a fixed-point value, behaves consistently across different scale factors. //