Skip to content

[feature]: add a function, rfqmath.FixedPointFromUint64_Decimal_DisplayΒ #1385

Open
@ZZiigguurraatt

Description

There is a lot of confusion when running a price oracle server on how to properly input the exchange rate. One example of this is here: https://lightningcommunity.slack.com/archives/C03B3556HQ8/p1738866875640909?thread_ts=1738748330.746709&cid=C03B3556HQ8 .

The basic-price-oracle example uses the rfqmath.FixedPointFromUint64 function, and that is where a lot of the confusions arises.

if transactionType == oraclerpc.TransactionType_PURCHASE {
// 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 {
// 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,
)

// FixedPointFromUint64 creates a new FixedPoint from the given integer and
// scale. Note that the input here should be *unscaled*.
func FixedPointFromUint64[N Int[N]](value uint64, scale uint8) FixedPoint[N] {
scaleN := NewInt[N]().FromFloat(math.Pow10(int(scale)))
coefficientN := NewInt[N]().FromUint64(value)
return FixedPoint[N]{
Coefficient: scaleN.Mul(coefficientN),
Scale: scale,
}
}

What is very confusing to new users is the "scale". It is recommended that this be the same as the decimal display that was defined when creating the asset. This leads users to think that the "coefficient" be defined in terms of decimal display asset units and then the exchange rate can be off by an order of magnitude of the decimal display. The "scale" parameter is recommended to be the same as the decimal display in order to reduce arithmetic round off error, but it doesn't really change the exchange rate itself.

I'd recommend a new function be created, rfqmath.FixedPointFromUint64_Decimal_Display, where the the exchange rate in terms of decimal display assets can be input, and then the decimal display digits as the second input. Then, convert the exchange rate from decimal display asset units to base asset units and use that as the coefficient input to rfqmath.FixedPointFromUint64. Then, also use the decimal display digits as the scale input to rfqmath.FixedPointFromUint64.

See also, the definition of FixedPoint:

// 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;
}
.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions