Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

README+docs: create document explaining decimal display and RFQ, add reference implementation #1059

Merged
merged 3 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,12 @@ updates the daemon's funds-custody material. Merely having the `lnd` seed phrase
is **NOT** enough to restore assets minted or received.
**WITHOUT BACKUP BEFORE DELETION, FUNDS ARE DESTROYED**.

## RFQ, asset decimal display, unit precision and price oracle

[Everything related to the RFQ (Request For Quote) system, the asset's currency
precision (decimal display) and the RFQ price oracle can be found in this
document](./docs/rfq-and-decimal-display.md).

## Submit feature requests

The [GitHub issue tracker](https://github.com/lightninglabs/taproot-assets/issues) can be used to request specific improvements or report bugs.
Expand Down
404 changes: 404 additions & 0 deletions docs/rfq-and-decimal-display.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ require (
gopkg.in/macaroon-bakery.v2 v2.1.0
gopkg.in/macaroon.v2 v2.1.0
modernc.org/sqlite v1.30.0
pgregory.net/rapid v1.1.0
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,8 @@ modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
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=
Expand Down
23 changes: 23 additions & 0 deletions rfq/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# RFQ

This package contains most code related to the business logic of the Request
For Quotes subsystem.

The high-level/conceptual explanation of [how RFQ (and related concepts such
as the decimal display value and price oracles) works, can be found
in this separate document](../docs/rfq-and-decimal-display.md).

The implementation of the [RFQ fixed point arithmetic can be found in the
`rfqmath` package](../rfqmath).

The actual [wire messages are located in the `rfqmsg`](../rfqmsg) package.

The [gRPC definitions of the RFQ methods can be found in the `taprpc/rfqrpc`
package](../taprpc/rfqrpc).

The [gRPC definitions of the price oracle methods can be found in the
`taprpc/priceoraclerpc` package](../taprpc/priceoraclerpc).

[An example implementation of a price oracle server implementing that RPC
interface with Golang can be found in
`docs/examples/basic-price-oracle`](../docs/examples/basic-price-oracle).
8 changes: 8 additions & 0 deletions rfqmath/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# RFQ math

This package contains code related to fixed point arithmetics used in RFQ
exchange rate calculations.

The high-level/conceptual explanation of [how RFQ (and related concepts such
as the decimal display value and price oracles) works, can be found
in this separate document](../docs/rfq-and-decimal-display.md).
213 changes: 213 additions & 0 deletions rfqmath/arithmetic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package rfqmath

import (
"math/big"

"golang.org/x/exp/constraints"
)

// Arithmetic defines the basic arithmetic operations. The structure of the
// interfaces allows for chaining the arithmetic operations.
type Arithmetic[N any] interface {
// Add returns the sum of the two numbers.
Add(N) N

// Mul returns the product of the two numbers.
Mul(N) N

// Sub returns the difference of the two numbers.
Sub(N) N

// Div returns the division of the two numbers.
Div(N) N
}

// Int is an interface that represents an integer types and the operations we
// care about w.r.t that type.
type Int[N any] interface {
// Arithmetic asserts that the target type of this interface satisfies
// the Arithmetic interface. This lets us get around limitations
// regarding recursive types in Go.
Arithmetic[N]

// Equals returns true if the two integers are equal.
Equals(other N) bool

// ToFloat converts the integer to a float.
ToFloat() float64

// FromFloat converts a float to the integer type.
FromFloat(float64) N

// ToUint64 converts the integer to a uint64.
ToUint64() uint64

// FromUint64 converts a uint64 to the integer type.
FromUint64(uint64) N
}

// NewInt creates a new integer of the target type.
func NewInt[N Int[N]]() N {
var n N
return n
}

// GoInt is a concrete implementation of the Int interface for the set of
// built-in integer types. It ends up mapping the integers to a uint64
// internally for operations.
type GoInt[T constraints.Unsigned] struct {
value T
}

// NewGoInt creates a new GoInt from the given integer.
func NewGoInt[T constraints.Unsigned](value T) GoInt[T] {
return GoInt[T]{
value: value,
}
}

// Add returns the sum of the two integers.
func (b GoInt[T]) Add(other GoInt[T]) GoInt[T] {
return GoInt[T]{
value: b.value + other.value,
}
}

// Mul returns the product of the two integers.
func (b GoInt[T]) Mul(other GoInt[T]) GoInt[T] {
return GoInt[T]{
value: b.value * other.value,
}
}

// Sub returns the difference of the two integers.
func (b GoInt[T]) Sub(other GoInt[T]) GoInt[T] {
return GoInt[T]{
value: b.value - other.value,
}
}

// Div returns the division of the two integers.
func (b GoInt[T]) Div(other GoInt[T]) GoInt[T] {
return GoInt[T]{
value: b.value / other.value,
}
}

// ToFloat converts the integer to a float.
func (b GoInt[T]) ToFloat() float64 {
return float64(b.value)
}

// FromFloat converts a float to the integer type.
func (b GoInt[T]) FromFloat(f float64) GoInt[T] {
b.value = T(f)
return b
}

// ToUint64 converts the integer to a uint64.
func (b GoInt[T]) ToUint64() uint64 {
return uint64(b.value)
}

// FromUint64 converts a uint64 to the integer type.
func (b GoInt[T]) FromUint64(u uint64) GoInt[T] {
b.value = T(u)
return b
}

// Equals returns true if the two integers are equal.
func (b GoInt[T]) Equals(other GoInt[T]) bool {
return b.value == other.value
}

// A compile-time constraint to ensure that the GoInt type implements the Int
// interface.
var _ Int[GoInt[uint]] = GoInt[uint]{}

// BigInt is a concrete implementation of the Int interface using Go's big
// integer type.
type BigInt struct {
value *big.Int
}

// NewBigInt creates a new BigInt from the given integer.
func NewBigInt(value *big.Int) BigInt {
return BigInt{
value: value,
}
}

// copyInt returns a copy of the internal big.Int. This is used to ensure we
// don't mutate the underlying bit.Int during arithmetic operations.
func (b BigInt) copyInt() *big.Int {
return new(big.Int).Set(b.value)
}

// Add returns the sum of the two integers.
func (b BigInt) Add(other BigInt) BigInt {
return BigInt{
value: b.copyInt().Add(b.value, other.value),
}
}

// Mul returns the product of the two integers.
func (b BigInt) Mul(other BigInt) BigInt {
return BigInt{
value: b.copyInt().Mul(b.value, other.value),
}
}

// Sub returns the difference of the two integers.
func (b BigInt) Sub(other BigInt) BigInt {
return BigInt{
value: b.copyInt().Sub(b.value, other.value),
}
}

// Div returns the division of the two integers.
func (b BigInt) Div(other BigInt) BigInt {
return BigInt{
value: b.copyInt().Div(b.value, other.value),
}
}

// ToFloat converts the integer to a float.
func (b BigInt) ToFloat() float64 {
floatVal, _ := b.value.Float64()
return floatVal
}

// FromFloat converts a float to the integer type.
func (b BigInt) FromFloat(f float64) BigInt {
if b.value == nil {
b.value = new(big.Int)
}

b.value.SetInt64(int64(f))
return b
}

// FromUint64 converts a uint64 to the integer type.
func (b BigInt) FromUint64(u uint64) BigInt {
if b.value == nil {
b.value = new(big.Int)
}

b.value.SetUint64(u)
return b
}

// ToUint64 converts the integer to a uint64.
func (b BigInt) ToUint64() uint64 {
return b.value.Uint64()
}

// Equals returns true if the two integers are equal.
func (b BigInt) Equals(other BigInt) bool {
return b.value.Cmp(other.value) == 0
}

// A compile-time constraint to ensure that the BigInt type implements the Int
// interface.
var _ Int[BigInt] = BigInt{}
Loading
Loading