rfqmath

package
v0.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 12, 2025 License: MIT Imports: 9 Imported by: 1

README

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.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// DefaultOnChainHtlcSat is the default amount that we consider as the
	// smallest HTLC amount that can be sent on-chain. This needs to be
	// greater than the dust limit for an HTLC.
	DefaultOnChainHtlcSat = lnwallet.DustLimitForSize(
		input.UnknownWitnessSize,
	)

	// DefaultOnChainHtlcMSat is the default amount that we consider as the
	// smallest HTLC amount that can be sent on-chain in milli-satoshis.
	DefaultOnChainHtlcMSat = lnwire.NewMSatFromSatoshis(
		DefaultOnChainHtlcSat,
	)
)

Functions

func MinTransportableMSat

func MinTransportableMSat(dustLimit lnwire.MilliSatoshi,
	rate BigIntFixedPoint) lnwire.MilliSatoshi

MinTransportableMSat computes the minimum amount of milli-satoshis that can be represented in a Lightning Network payment when transferring an asset, given the asset rate and the constant HTLC dust limit. This function can be used to enforce a minimum payable amount with assets, as any invoice amount below this value would be uneconomical as the total amount sent would exceed the total invoice amount.

func NewInt

func NewInt[N Int[N]]() N

NewInt creates a new integer of the target type.

func UnitsToMilliSatoshi

func UnitsToMilliSatoshi[N Int[N]](assetUnits,
	unitsPerBtc FixedPoint[N]) lnwire.MilliSatoshi

UnitsToMilliSatoshi converts the given number of asset units to a milli-satoshi amount, using the given price in units per bitcoin as a fixed point in the asset's desired resolution (scale equal to decimal display).

Given the amount of asset units (U), and the number of units per BTC (Y), we 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.

Types

type Arithmetic

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
}

Arithmetic defines the basic arithmetic operations. The structure of the interfaces allows for chaining the arithmetic operations.

type BigInt

type BigInt struct {
	// contains filtered or unexported fields
}

BigInt is a concrete implementation of the Int interface using Go's big integer type.

func NewBigInt

func NewBigInt(value *big.Int) BigInt

NewBigInt creates a new BigInt from the given integer.

func NewBigIntFromUint64

func NewBigIntFromUint64(value uint64) BigInt

NewBigIntFromUint64 creates a new BigInt from the given uint64.

func (BigInt) Add

func (b BigInt) Add(other BigInt) BigInt

Add returns the sum of the two integers.

func (BigInt) Bytes

func (b BigInt) Bytes() []byte

Bytes returns the absolute value of b as a big-endian byte slice.

func (BigInt) Div

func (b BigInt) Div(other BigInt) BigInt

Div returns the division of the two integers.

func (BigInt) Equals

func (b BigInt) Equals(other BigInt) bool

Equals returns true if the two integers are equal.

func (BigInt) FromBytes

func (b BigInt) FromBytes(buf []byte) BigInt

FromBytes interprets `buf` as a big-endian unsigned integer and returns a new BigInt with that value.

func (BigInt) FromFloat

func (b BigInt) FromFloat(f float64) BigInt

FromFloat converts a float to the integer type.

func (BigInt) FromUint64

func (b BigInt) FromUint64(u uint64) BigInt

FromUint64 converts a uint64 to the integer type.

func (BigInt) Gt

func (b BigInt) Gt(other BigInt) bool

Gt returns true if the integer is greater than the other integer.

func (BigInt) Gte

func (b BigInt) Gte(other BigInt) bool

Gte returns true if the integer is greater than or equal to the other integer.

func (BigInt) Mul

func (b BigInt) Mul(other BigInt) BigInt

Mul returns the product of the two integers.

func (BigInt) String

func (b BigInt) String() string

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 (BigInt) Sub

func (b BigInt) Sub(other BigInt) BigInt

Sub returns the difference of the two integers.

func (BigInt) ToFloat

func (b BigInt) ToFloat() float64

ToFloat converts the integer to a float.

func (BigInt) ToUint64

func (b BigInt) ToUint64() uint64

ToUint64 converts the integer to a uint64.

type BigIntFixedPoint

type BigIntFixedPoint = FixedPoint[BigInt]

BigIntFixedPoint is a fixed-point number with a BigInt coefficient.

func MinTransportableUnits

func MinTransportableUnits(dustLimit lnwire.MilliSatoshi,
	rate BigIntFixedPoint) BigIntFixedPoint

MinTransportableUnits computes the minimum number of transportable units of an asset given its asset rate and the constant HTLC dust limit. This function can be used to enforce a minimum invoice amount to prevent forwarding failures due to invalid fees.

Given a wallet end user A, an edge node B, an asset rate of 100 milli- satoshi per asset unit and a flat 0.1% routing fee (to simplify the scenario), the following invoice based receive events can occur:

  1. Success case: User A creates an invoice over 5,000 units (500,000 milli- satoshis) that is paid by the network. An HTLC over 500,500 milli- satoshis arrives at B. B converts the HTLC to 5,000 units and sends 354,000 milli-satoshis to A. A receives a total "worth" of 854,000 milli-satoshis, which is already more than the invoice amount. But at least the forwarding rule in `lnd` for B is not violated (outgoing amount mSat < incoming amount mSat).
  2. Failure case: User A creates an invoice over 3,530 units (353,000 milli- satoshis) that is paid by the network. An HTLC over 353,530 milli- satoshis arrives at B. B converts the HTLC to 3,530 units and sends 354,000 milli-satoshis to A. This fails in the `lnd` forwarding logic, because the outgoing amount (354,000 milli-satoshis) is greater than the incoming amount (353,530 milli-satoshis).

func NewBigIntFixedPoint

func NewBigIntFixedPoint(coefficient uint64, scale uint8) BigIntFixedPoint

NewBigIntFixedPoint creates a new BigInt fixed-point given a coefficient and scale.

type FixedPoint

type FixedPoint[T Int[T]] struct {
	// Coefficient is the value of the FixedPoint integer.
	Coefficient T

	// Scale is used to represent the fractional component. This always
	// represents a power of 10. Eg: a scale value of 2 (two decimal
	// places) maps to a multiplication by 100.
	Scale uint8
}

FixedPoint is used to represent fixed point arithmetic for currency related calculations. A fixed point consists of a value, and a scale. The value is the integer representation of the number. The scale is used to represent the fractional/decimal component.

func FixedPointFromUint64

func FixedPointFromUint64[N Int[N]](value uint64, scale uint8) FixedPoint[N]

FixedPointFromUint64 creates a new FixedPoint from the given integer and scale. Note that the input here should be *unscaled*.

func MilliSatoshiToUnits

func MilliSatoshiToUnits[N Int[N]](milliSat lnwire.MilliSatoshi,
	unitsPerBtc FixedPoint[N]) FixedPoint[N]

MilliSatoshiToUnits converts the given milli-satoshi amount to units using the given price in units per bitcoin as a fixed point in the asset's desired resolution (scale equal to decimal display).

Given the amount of mSat (X), and the number of units per BTC (Y), we can compute the total amount of units (U) as follows:

  • U = (X / M) * Y
  • where M is the number of mSAT in a BTC (100,000,000,000).

func (FixedPoint[T]) Div

func (f FixedPoint[T]) Div(other FixedPoint[T]) FixedPoint[T]

Div returns a new FixedPoint that is the result of dividing the existing int by the passed one.

NOTE: This function assumes that the scales of the two FixedPoint values are identical. If the scales differ, the result may be incorrect.

func (FixedPoint[T]) Equals

func (f FixedPoint[T]) Equals(other FixedPoint[T]) bool

Equals returns true if the two FixedPoint values are equal.

func (FixedPoint[T]) Mul

func (f FixedPoint[T]) Mul(other FixedPoint[T]) FixedPoint[T]

Mul returns a new FixedPoint that is the result of multiplying the existing int by the passed one.

NOTE: This function assumes that the scales of the two FixedPoint values are identical. If the scales differ, the result may be incorrect.

func (FixedPoint[T]) ScaleTo

func (f FixedPoint[T]) ScaleTo(newScale uint8) FixedPoint[T]

ScaleTo returns a new FixedPoint that is scaled up or down to the given scale.

func (FixedPoint[T]) SetIntValue

func (f FixedPoint[T]) SetIntValue(value T) FixedPoint[T]

SetIntValue assigns the specified integer value to the FixedPoint. The coefficient is set to the given value, and the scale is reset to 0.

func (FixedPoint[T]) String

func (f FixedPoint[T]) String() string

String returns the string version of the fixed point value.

func (FixedPoint[T]) ToFloat64

func (f FixedPoint[T]) ToFloat64() float64

ToFloat64 returns a float64 representation of the FixedPoint value.

func (FixedPoint[T]) ToUint64

func (f FixedPoint[T]) ToUint64() uint64

ToUint64 returns a new FixedPoint that is scaled down from the existing scale and mapped to a uint64 representing the amount of units. This should be used to go from FixedPoint to an amount of "units".

func (FixedPoint[T]) WithinTolerance

func (f FixedPoint[T]) WithinTolerance(
	other FixedPoint[T], tolerancePpm T) (bool, error)

WithinTolerance returns true if the two FixedPoint values are within the given tolerance, specified in parts per million (PPM).

The tolerance is applied relative to the larger of the two values to ensure that a 100% tolerance (1,000,000 PPM) always results in a match for any two nonzero values.

This max-based approach (e.g. ask) is more lenient than using the smaller value (e.g., bid) as the reference. For example, if the two values are 100 and 105, a 5% tolerance (50,000 PPM) allows a maximum difference of: - Bid-based: 100 × 0.05 = 5 (so 105 is the limit) - Max-based: 105 × 0.05 = 5.25 (so 105 is still within tolerance)

This means max-based tolerance accepts slightly wider spreads, making it less strict in bid-ask scenarios.

type GoInt

type GoInt[T constraints.Unsigned] struct {
	// contains filtered or unexported fields
}

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.

func NewGoInt

func NewGoInt[T constraints.Unsigned](value T) GoInt[T]

NewGoInt creates a new GoInt from the given integer.

func (GoInt[T]) Add

func (b GoInt[T]) Add(other GoInt[T]) GoInt[T]

Add returns the sum of the two integers.

func (GoInt[T]) Div

func (b GoInt[T]) Div(other GoInt[T]) GoInt[T]

Div returns the division of the two integers.

func (GoInt[T]) Equals

func (b GoInt[T]) Equals(other GoInt[T]) bool

Equals returns true if the two integers are equal.

func (GoInt[T]) FromFloat

func (b GoInt[T]) FromFloat(f float64) GoInt[T]

FromFloat converts a float to the integer type.

func (GoInt[T]) FromUint64

func (b GoInt[T]) FromUint64(u uint64) GoInt[T]

FromUint64 converts a uint64 to the integer type.

func (GoInt[T]) Gt

func (b GoInt[T]) Gt(other GoInt[T]) bool

Gt returns true if the integer is greater than the other integer.

func (GoInt[T]) Gte

func (b GoInt[T]) Gte(other GoInt[T]) bool

Gte returns true if the integer is greater than or equal to the other integer.

func (GoInt[T]) Mul

func (b GoInt[T]) Mul(other GoInt[T]) GoInt[T]

Mul returns the product of the two integers.

func (GoInt[T]) Sub

func (b GoInt[T]) Sub(other GoInt[T]) GoInt[T]

Sub returns the difference of the two integers.

func (GoInt[T]) ToFloat

func (b GoInt[T]) ToFloat() float64

ToFloat converts the integer to a float.

func (GoInt[T]) ToUint64

func (b GoInt[T]) ToUint64() uint64

ToUint64 converts the integer to a uint64.

type Int

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

	// Gt returns true if the integer is greater than the other integer.
	Gt(other N) bool

	// Gte returns true if the integer is greater than or equal to the other
	// integer.
	Gte(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
}

Int is an interface that represents an integer types and the operations we care about w.r.t that type.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
JackTT - Gopher 🇻🇳