// Copyright 2023 The AthanorLabs/atomic-swap Authors // SPDX-License-Identifier: LGPL-3.0-only package coins import ( "fmt" "github.com/cockroachdb/apd/v3" ) // ValidatePositive is for doing additional input validation on apd.Decimal values // that should only contain positive values (like min, max and provided amounts). func ValidatePositive(jsonFieldName string, maxDecimals uint8, value *apd.Decimal) error { if value == nil { return fmt.Errorf("%q is not set", jsonFieldName) } if value.IsZero() { return fmt.Errorf("%q must be non-zero", jsonFieldName) } if value.Negative { return fmt.Errorf("%q cannot be negative", jsonFieldName) } if value.Form != apd.Finite { return fmt.Errorf("%q must be finite", jsonFieldName) } // In most cases, this line won't do anything. If the coefficient is divisible // by one or more multiples of 10, the zeros are chopped off and added to the // exponent (same external value, but different internal representation). _, _ = value.Reduce(value) // We could probably go lower, but something is definitely suspicious if // someone is sending us amounts with more than 100 digits. The check // below does not differentiate between digits before/after the Decimal // point. numDigits := value.NumDigits() // number of digits in the coefficient if numDigits > MaxCoinPrecision { return fmt.Errorf("%q has too many digits", jsonFieldName) } // We are calling digits after the decimal point "decimals". Since we reduced // the value above, each negative exponent value represents a decimal point. if value.Exponent < -int32(maxDecimals) { return fmt.Errorf("%q has too many decimal points; found=%d max=%d", jsonFieldName, -value.Exponent, maxDecimals) } return nil }