Skip to content

Commit

Permalink
Improve QuoteToBaseQuantums (#1554)
Browse files Browse the repository at this point in the history
  • Loading branch information
BrendanChou authored May 21, 2024
1 parent 5ed80b6 commit 4278dd3
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 21 deletions.
35 changes: 14 additions & 21 deletions protocol/lib/quantums.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,37 +63,30 @@ func BaseToQuoteQuantums(
// quoteQuantums / priceValue /
// 10^(priceExponent + baseCurrencyAtomicResolution - quoteCurrencyAtomicResolution)
//
// The result is rounded down.
// The result is rounded towards zero.
func QuoteToBaseQuantums(
bigQuoteQuantums *big.Int,
baseCurrencyAtomicResolution int32,
priceValue uint64,
priceExponent int32,
) (bigNotional *big.Int) {
// Determine the non-exponent part of the equation.
// We perform all calculations using positive rationals for consistent rounding.
isLong := bigQuoteQuantums.Sign() >= 0
ratAbsQuoteQuantums := new(big.Rat).Abs(
new(big.Rat).SetInt(bigQuoteQuantums),
)
ratPrice := new(big.Rat).SetUint64(priceValue)
ratQuoteQuantumsDivPrice := new(big.Rat).Quo(ratAbsQuoteQuantums, ratPrice)
// Initialize result to quoteQuantums.
result := new(big.Int).Set(bigQuoteQuantums)

// Determine the absolute value of the return value.
// Divide result (towards zero) by 10^(exponent).
exponent := priceExponent + baseCurrencyAtomicResolution - QuoteCurrencyAtomicResolution
ratBaseQuantums := new(big.Rat).Quo(
ratQuoteQuantumsDivPrice,
RatPow10(exponent),
)
power10Exponent := BigPow10(uint64(AbsInt32(exponent)))
if exponent > 0 {
result.Quo(result, power10Exponent)
} else {
result.Mul(result, power10Exponent)
}

// Round down.
bigBaseQuantums := BigRatRound(ratBaseQuantums, false)
// Divide result (towards zero) by priceValue.
// If there are two divisions, it is okay to do them separately as the result is the same.
result.Quo(result, new(big.Int).SetUint64(priceValue))

// Flip the sign of the return value if necessary.
if !isLong {
bigBaseQuantums.Neg(bigBaseQuantums)
}
return bigBaseQuantums
return result
}

// multiplyByPrice multiples a value by price, factoring in exponents of base
Expand Down
30 changes: 30 additions & 0 deletions protocol/lib/quantums_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,33 @@ func BenchmarkBaseToQuoteQuantums(b *testing.B) {
expected2, _ := new(big.Int).SetString("2276555874282755105905825041901000000000", 10)
require.Equal(b, expected2, result2)
}

func BenchmarkQuoteToBaseQuantums(b *testing.B) {
value, _ := new(big.Int).SetString("18446744073709551610", 10)
baseCurrencyAtomicResolution := int32(-8)
priceValue := uint64(1234123412341)
priceExponent1 := int32(-10)
priceExponent2 := int32(6)
var result1 *big.Int
var result2 *big.Int

for i := 0; i < b.N; i++ {
result1 = lib.QuoteToBaseQuantums(
value,
baseCurrencyAtomicResolution,
priceValue,
priceExponent1,
)
result2 = lib.QuoteToBaseQuantums(
value,
baseCurrencyAtomicResolution,
priceValue,
priceExponent2,
)
}

expected1, _ := new(big.Int).SetString("14947244245790664347", 10)
require.Equal(b, expected1, result1)
expected2, _ := new(big.Int).SetString("1494", 10)
require.Equal(b, expected2, result2)
}

0 comments on commit 4278dd3

Please sign in to comment.