mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-11-27 07:48:44 +00:00
Use decimal places as defined by constants
Also check if SompiPerKaspa is multiple of 10
This commit is contained in:
parent
97c7e8e9e4
commit
0bd5a9aa4f
@ -2,10 +2,13 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
"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
|
// 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
|
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) {
|
func KasToSompi(amount string) (uint64, error) {
|
||||||
err := ValidateAmountFormat(amount)
|
err := validateAmountFormat(amount)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@ -30,14 +33,36 @@ func KasToSompi(amount string) (uint64, error) {
|
|||||||
parts := strings.Split(amount, ".")
|
parts := strings.Split(amount, ".")
|
||||||
amountStr := ""
|
amountStr := ""
|
||||||
|
|
||||||
if len(parts) == 2 {
|
if constants.SompiPerKaspa%10 != 0 {
|
||||||
amountStr = fmt.Sprintf("%s%-*s", parts[0], 8, parts[1]) // Padded with spaces at the end to fill for missing decimals: Sample "0.01234 "
|
return 0, errors.Errorf("Unable to convert to sompi when SompiPerKaspa is not a multiple of 10")
|
||||||
amountStr = strings.ReplaceAll(amountStr, " ", "0") // Make the spaces be 0s. Sample "0.012340000"
|
|
||||||
} else {
|
|
||||||
amountStr = fmt.Sprintf("%s00000000", parts[0])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
convertedAmount, err := strconv.ParseUint(amountStr, 10, 64)
|
||||||
|
|
||||||
return convertedAmount, err
|
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
|
||||||
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -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
|
|
||||||
}
|
|
||||||
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user