Use decimal places as defined by constants

Also check if SompiPerKaspa is multiple of 10
This commit is contained in:
coderofstuff 2023-09-22 19:41:50 -06:00
parent 97c7e8e9e4
commit 0bd5a9aa4f
4 changed files with 78 additions and 84 deletions

View File

@ -2,10 +2,13 @@ package utils
import (
"fmt"
"math"
"regexp"
"strconv"
"strings"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/pkg/errors"
)
// FormatKas takes the amount of sompis as uint64, and returns amount of KAS with 8 decimal places
@ -17,9 +20,9 @@ func FormatKas(amount uint64) string {
return res
}
// Takes in a string representation of the Kas value to convert to Sompi
// KasToSompi takes in a string representation of the Kas value to convert to Sompi
func KasToSompi(amount string) (uint64, error) {
err := ValidateAmountFormat(amount)
err := validateAmountFormat(amount)
if err != nil {
return 0, err
@ -30,14 +33,36 @@ func KasToSompi(amount string) (uint64, error) {
parts := strings.Split(amount, ".")
amountStr := ""
if len(parts) == 2 {
amountStr = fmt.Sprintf("%s%-*s", parts[0], 8, parts[1]) // Padded with spaces at the end to fill for missing decimals: Sample "0.01234 "
amountStr = strings.ReplaceAll(amountStr, " ", "0") // Make the spaces be 0s. Sample "0.012340000"
} else {
amountStr = fmt.Sprintf("%s00000000", parts[0])
if constants.SompiPerKaspa%10 != 0 {
return 0, errors.Errorf("Unable to convert to sompi when SompiPerKaspa is not a multiple of 10")
}
decimalPlaces := int(math.Log10(constants.SompiPerKaspa))
decimalStr := ""
if len(parts) == 2 {
decimalStr = parts[1]
}
amountStr = fmt.Sprintf("%s%-*s", parts[0], decimalPlaces, decimalStr) // Padded with spaces at the end to fill for missing decimals: Sample "0.01234 "
amountStr = strings.ReplaceAll(amountStr, " ", "0") // Make the spaces be 0s. Sample "0.012340000"
convertedAmount, err := strconv.ParseUint(amountStr, 10, 64)
return convertedAmount, err
}
func validateAmountFormat(amount string) error {
// Check whether it's an integer, or a float with max 8 digits
match, err := regexp.MatchString("^([1-9]\\d{0,11}|0)(\\.\\d{0,8})?$", amount)
if !match {
return errors.Errorf("Invalid send amount")
}
if err != nil {
return err
}
return nil
}

View File

@ -42,3 +42,49 @@ func TestKasToSompi(t *testing.T) {
}
}
}
func TestValidateAmountFormat(t *testing.T) {
validCases := []string{
"0",
"1",
"1.0",
"0.1",
"0.12345678",
"111111111111.11111111", // 12 digits to the left of decimal, 8 digits to the right
"184467440737.09551615", // Maximum input that can be represented in sompi later
"184467440737.09551616", // Cannot be represented in sompi, but we'll acccept for "correct format"
"999999999999.99999999", // Cannot be represented in sompi, but we'll acccept for "correct format"
}
for _, testCase := range validCases {
err := validateAmountFormat(testCase)
if err != nil {
t.Error(err)
}
}
invalidCases := []string{
"",
"a",
"-1",
"0.123456789", // 9 decimal digits
".1", // decimal but no integer component
"0a", // Extra character
"0000000000000", // 13 zeros
"012", // Int padded with zero
"00.1", // Decimal padded with zeros
"111111111111111111111", // all digits
"111111111111A11111111", // non-period/non-digit where decimal would be
"000000000000.00000000", // all zeros
"kaspa", // all text
}
for _, testCase := range invalidCases {
err := validateAmountFormat(testCase)
if err == nil {
t.Errorf("Expected an error but succeeded validation for test case %s", testCase)
}
}
}

View File

@ -1,26 +0,0 @@
package utils
import (
"regexp"
"github.com/pkg/errors"
)
/**
* 1. May be an integer (no decimal components)
* 2. May be float with up to 8 decimal places
*/
func ValidateAmountFormat(amount string) error {
// Check whether it's an integer, or a float with max 8 digits
match, err := regexp.MatchString("^([1-9]\\d{0,11}|0)(\\.\\d{0,8})?$", amount)
if !match {
return errors.Errorf("Invalid send amount")
}
if err != nil {
return err
}
return nil
}

View File

@ -1,51 +0,0 @@
package utils
import (
"testing"
)
func TestValidateAmountFormat(t *testing.T) {
validCases := []string{
"0",
"1",
"1.0",
"0.1",
"0.12345678",
"111111111111.11111111", // 12 digits to the left of decimal, 8 digits to the right
"184467440737.09551615", // Maximum input that can be represented in sompi later
"184467440737.09551616", // Cannot be represented in sompi, but we'll acccept for "correct format"
"999999999999.99999999", // Cannot be represented in sompi, but we'll acccept for "correct format"
}
for _, testCase := range validCases {
err := ValidateAmountFormat(testCase)
if err != nil {
t.Error(err)
}
}
invalidCases := []string{
"",
"a",
"-1",
"0.123456789", // 9 decimal digits
".1", // decimal but no integer component
"0a", // Extra character
"0000000000000", // 13 zeros
"012", // Int padded with zero
"00.1", // Decimal padded with zeros
"111111111111111111111", // all digits
"111111111111A11111111", // non-period/non-digit where decimal would be
"000000000000.00000000", // all zeros
"kaspa", // all text
}
for _, testCase := range invalidCases {
err := ValidateAmountFormat(testCase)
if err == nil {
t.Errorf("Expected an error but succeeded validation for test case %s", testCase)
}
}
}