Skip to content

Commit 47dd304

Browse files
committed
rfqmath: add AddTolerance helper
1 parent 52be50c commit 47dd304

File tree

3 files changed

+65
-9
lines changed

3 files changed

+65
-9
lines changed

rfqmath/fixed_point.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,23 @@ func (f FixedPoint[T]) WithinTolerance(
186186
return result, nil
187187
}
188188

189+
// AddTolerance applies the given tolerance expressed in parts per million (ppm)
190+
// to the provided amount.
191+
func AddTolerance(value, tolerancePpm BigInt) BigInt {
192+
// A placeholder variable for ppm value denominator (1 million).
193+
ppmBase := NewBigIntFromUint64(1_000_000)
194+
195+
// Convert the tolerancePpm value to the actual units that express this
196+
// margin.
197+
toleranceUnits := value.Mul(tolerancePpm).Div(ppmBase)
198+
199+
res := value.Add(toleranceUnits)
200+
201+
// We now add the tolerance margin to the original value and return the
202+
// result.
203+
return res
204+
}
205+
189206
// FixedPointFromUint64 creates a new FixedPoint from the given integer and
190207
// scale. Note that the input here should be *unscaled*.
191208
func FixedPointFromUint64[N Int[N]](value uint64, scale uint8) FixedPoint[N] {

rfqmath/fixed_point_test.go

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,44 @@ func testWithinToleranceZeroTolerance(t *rapid.T) {
396396
require.True(t, result)
397397
}
398398

399+
// testAddToleranceProp is a property-based test which tests that the
400+
// AddTolerance helper correctly applies the provided tolerance margin to any
401+
// given value.
402+
func testAddToleranceProp(t *rapid.T) {
403+
value := NewBigIntFromUint64(rapid.Uint64Min(1).Draw(t, "value"))
404+
tolerancePpm := NewBigIntFromUint64(
405+
rapid.Uint64Range(0, 1_000_000).Draw(t, "tolerance_ppm"),
406+
)
407+
408+
result := AddTolerance(value, tolerancePpm)
409+
410+
if tolerancePpm.ToUint64() == 0 {
411+
require.True(t, result.Equals(value))
412+
return
413+
}
414+
415+
// First off, let's just check that the result is at all greater than
416+
// the input.
417+
require.True(t, result.Gte(value))
418+
419+
// Let's now convert the values to a fixed point type in order to use
420+
// the WithinTolerance method.
421+
valueFixed := BigIntFixedPoint{
422+
Coefficient: value,
423+
Scale: 0,
424+
}
425+
resultFixed := BigIntFixedPoint{
426+
Coefficient: result,
427+
Scale: 0,
428+
}
429+
430+
// The value with the applied tolerance and the original value should be
431+
// within tolerance.
432+
res, err := resultFixed.WithinTolerance(valueFixed, tolerancePpm)
433+
require.NoError(t, err)
434+
require.True(t, res)
435+
}
436+
399437
// testWithinToleranceSymmetric is a property-based test which ensures that the
400438
// WithinTolerance method is symmetric (swapping the order of the fixed-point
401439
// values does not change the result).
@@ -600,6 +638,11 @@ func testWithinTolerance(t *testing.T) {
600638
"within_tolerance_float_reproduce",
601639
rapid.MakeCheck(testWithinToleranceFloatReproduce),
602640
)
641+
642+
t.Run(
643+
"add_tolerance_property",
644+
rapid.MakeCheck(testAddToleranceProp),
645+
)
603646
}
604647

605648
// TestFixedPoint runs a series of property-based tests on the FixedPoint type
@@ -619,5 +662,5 @@ func TestFixedPoint(t *testing.T) {
619662

620663
t.Run("from_uint64", rapid.MakeCheck(testFromUint64[BigInt]))
621664

622-
t.Run("within_tolerance", testWithinTolerance)
665+
t.Run("tolerance", testWithinTolerance)
623666
}

rpcserver.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7953,19 +7953,15 @@ func calculateAssetMaxAmount(ctx context.Context, priceOracle rfq.PriceOracle,
79537953
// the agreed upon quote may be different. If we don't add this safety
79547954
// window the peer may allow a routable amount that evaluates to less
79557955
// than what we ask for.
7956-
tolerance := rfqmath.NewBigIntFromUint64(deviationPPM)
7957-
7958-
// Calculate the tolerance margin.
7959-
toleranceUnits := maxMathUnits.Mul(tolerance).Div(
7960-
rfqmath.NewBigIntFromUint64(1_000_000),
7961-
)
7962-
79637956
// Apply the tolerance margin twice. Once due to the ask/bid price
79647957
// deviation that may occur during rfq negotiation, and once for the
79657958
// price movement that may occur between querying the oracle and
79667959
// acquiring the quote. We don't really care about this margin being too
79677960
// big, this only affects the max units our peer agrees to route.
7968-
maxMathUnits = maxMathUnits.Add(toleranceUnits).Add(toleranceUnits)
7961+
tolerance := rfqmath.NewBigIntFromUint64(deviationPPM)
7962+
7963+
maxMathUnits = rfqmath.AddTolerance(maxMathUnits, tolerance)
7964+
maxMathUnits = rfqmath.AddTolerance(maxMathUnits, tolerance)
79697965

79707966
return maxMathUnits.ToUint64(), nil
79717967
}

0 commit comments

Comments
 (0)