Skip to content

Commit

Permalink
Merge pull request #1059 from guggero/rfq-doc
Browse files Browse the repository at this point in the history
README+docs: create document explaining decimal display and RFQ, add reference implementation
  • Loading branch information
ffranr committed Sep 16, 2024
2 parents 2f0947d + b4208ac commit 7496ab3
Show file tree
Hide file tree
Showing 60 changed files with 2,808 additions and 0 deletions.
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

0 comments on commit 7496ab3

Please sign in to comment.