util: implement FixedN from string

When working with NEP5 contracts we frequently need
to parse fixed-point decimals with arbitrary precision.
This commit is contained in:
Evgenii Stratonikov 2020-03-05 20:05:52 +03:00
parent cdeba6d417
commit d447064515
2 changed files with 30 additions and 4 deletions

View file

@ -3,6 +3,7 @@ package util
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"math"
"strconv" "strconv"
"strings" "strings"
@ -71,25 +72,36 @@ func Fixed8FromFloat(val float64) Fixed8 {
// Fixed8FromString parses s which must be a fixed point number // Fixed8FromString parses s which must be a fixed point number
// with precision up to 10^-8 // with precision up to 10^-8
func Fixed8FromString(s string) (Fixed8, error) { func Fixed8FromString(s string) (Fixed8, error) {
num, err := FixedNFromString(s, precision)
if err != nil {
return 0, err
}
return Fixed8(num), err
}
// FixedNFromString parses s which must be a fixed point number
// with precision 10^-d.
func FixedNFromString(s string, precision int) (int64, error) {
parts := strings.SplitN(s, ".", 2) parts := strings.SplitN(s, ".", 2)
d := int64(math.Pow10(precision))
ip, err := strconv.ParseInt(parts[0], 10, 64) ip, err := strconv.ParseInt(parts[0], 10, 64)
if err != nil { if err != nil {
return 0, errInvalidString return 0, errInvalidString
} else if len(parts) == 1 { } else if len(parts) == 1 {
return Fixed8(ip * decimals), nil return ip * d, nil
} }
fp, err := strconv.ParseInt(parts[1], 10, 64) fp, err := strconv.ParseInt(parts[1], 10, 64)
if err != nil || fp >= decimals { if err != nil || fp >= d {
return 0, errInvalidString return 0, errInvalidString
} }
for i := len(parts[1]); i < precision; i++ { for i := len(parts[1]); i < precision; i++ {
fp *= 10 fp *= 10
} }
if ip < 0 { if ip < 0 {
return Fixed8(ip*decimals - fp), nil return ip*d - fp, nil
} }
return Fixed8(ip*decimals + fp), nil return ip*d + fp, nil
} }
// UnmarshalJSON implements the json unmarshaller interface. // UnmarshalJSON implements the json unmarshaller interface.

View file

@ -85,6 +85,20 @@ func TestFixed8FromString(t *testing.T) {
assert.Error(t, err) assert.Error(t, err)
} }
func TestFixedNFromString(t *testing.T) {
val := "123.456"
num, err := FixedNFromString(val, 3)
require.NoError(t, err)
require.EqualValues(t, 123456, num)
num, err = FixedNFromString(val, 4)
require.NoError(t, err)
require.EqualValues(t, 1234560, num)
_, err = FixedNFromString(val, 2)
require.Error(t, err)
}
func TestSatoshi(t *testing.T) { func TestSatoshi(t *testing.T) {
satoshif8 := Satoshi() satoshif8 := Satoshi()
assert.Equal(t, "0.00000001", satoshif8.String()) assert.Equal(t, "0.00000001", satoshif8.String())