From 79f363e94e37090ce5618f574aa920a6eaa3f8d7 Mon Sep 17 00:00:00 2001 From: containerman17 <8990432+containerman17@users.noreply.github.com> Date: Wed, 2 Oct 2024 11:53:59 +0900 Subject: [PATCH] Standardize decimals (#1620) --- cli/cli.go | 1 - cli/key.go | 4 +-- cli/prompt/prompt.go | 5 ++-- cli/spam.go | 4 +-- consts/consts.go | 1 + docs/tutorials/morpheusvm/options.md | 8 +---- .../morpheusvm/cmd/morpheus-cli/cmd/action.go | 3 +- .../cmd/morpheus-cli/cmd/handler.go | 6 +--- .../cmd/morpheus-cli/cmd/resolutions.go | 6 ++-- .../morpheusvm/cmd/morpheus-cli/cmd/spam.go | 2 +- examples/morpheusvm/vm/client.go | 2 +- .../cmd/vmwithcontracts-cli/cmd/action.go | 7 ++--- .../cmd/vmwithcontracts-cli/cmd/handler.go | 2 +- .../vmwithcontracts-cli/cmd/resolutions.go | 6 ++-- .../cmd/vmwithcontracts-cli/cmd/spam.go | 2 +- examples/vmwithcontracts/vm/client.go | 2 +- utils/utils.go | 8 ++--- utils/utils_test.go | 29 +++++++++++++++++++ 18 files changed, 57 insertions(+), 41 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index af80e9dddd..01fc240b6a 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -14,7 +14,6 @@ import ( type Controller interface { DatabasePath() string Symbol() string - Decimals() uint8 GetParser(string) (chain.Parser, error) HandleTx(*chain.Transaction, *chain.Result) LookupBalance(address codec.Address, uri string) (uint64, error) diff --git a/cli/key.go b/cli/key.go index f1fa6c0ee1..d433a51438 100644 --- a/cli/key.go +++ b/cli/key.go @@ -36,7 +36,7 @@ func (h *Handler) SetKey() error { "%d) {{cyan}}address:{{/}} %s {{cyan}}balance:{{/}} %s %s\n", i, addrStr, - utils.FormatBalance(balance, h.c.Decimals()), + utils.FormatBalance(balance), h.c.Symbol(), ) } @@ -73,7 +73,7 @@ func (h *Handler) Balance(checkAllChains bool) error { utils.Outf( "{{cyan}}address:{{/}} %s {{cyan}}balance:{{/}} %s %s\n", addr, - utils.FormatBalance(balance, h.c.Decimals()), + utils.FormatBalance(balance), h.c.Symbol(), ) } diff --git a/cli/prompt/prompt.go b/cli/prompt/prompt.go index ee3a89605e..a5febf57b5 100644 --- a/cli/prompt/prompt.go +++ b/cli/prompt/prompt.go @@ -124,7 +124,6 @@ func Asset(label string, symbol string, allowNative bool) (ids.ID, error) { func Amount( label string, - decimals uint8, balance uint64, f func(input uint64) error, ) (uint64, error) { @@ -134,7 +133,7 @@ func Amount( if len(input) == 0 { return ErrInputEmpty } - amount, err := utils.ParseBalance(input, decimals) + amount, err := utils.ParseBalance(input) if err != nil { return err } @@ -152,7 +151,7 @@ func Amount( return 0, err } rawAmount = strings.TrimSpace(rawAmount) - return utils.ParseBalance(rawAmount, decimals) + return utils.ParseBalance(rawAmount) } func Int( diff --git a/cli/spam.go b/cli/spam.go index fa2b5ae3cd..00147651e4 100644 --- a/cli/spam.go +++ b/cli/spam.go @@ -204,7 +204,7 @@ func (h *Handler) Spam(sh SpamHelper) error { distAmount := (balance - withholding) / uint64(numAccounts) utils.Outf( "{{yellow}}distributing funds to each account:{{/}} %s %s\n", - utils.FormatBalance(distAmount, h.c.Decimals()), + utils.FormatBalance(distAmount), h.c.Symbol(), ) accounts := make([]*PrivateKey, numAccounts) @@ -455,7 +455,7 @@ func (h *Handler) Spam(sh SpamHelper) error { } utils.Outf( "{{yellow}}returned funds:{{/}} %s %s\n", - utils.FormatBalance(returnedBalance, h.c.Decimals()), + utils.FormatBalance(returnedBalance), h.c.Symbol(), ) return nil diff --git a/consts/consts.go b/consts/consts.go index 35861ca03b..377c8f8d21 100644 --- a/consts/consts.go +++ b/consts/consts.go @@ -30,4 +30,5 @@ const ( MaxUint64 = ^uint64(0) MaxFloat64 = math.MaxFloat64 MillisecondsPerSecond = 1000 + Decimals = 9 ) diff --git a/docs/tutorials/morpheusvm/options.md b/docs/tutorials/morpheusvm/options.md index e83b9300b2..53fc743f67 100644 --- a/docs/tutorials/morpheusvm/options.md +++ b/docs/tutorials/morpheusvm/options.md @@ -29,12 +29,6 @@ func GetBalanceFromState( This function is almost identical to `getBalance()` except that we are passing along `f` of type `ReadState` instead of `im` of type `state.Immutable`. -We also need to specify the precision of our VM token. To do this, go to -`consts/consts.go` and add the following constant: - -```golang -const Decimals = 9 -``` ## Getting Started @@ -233,7 +227,7 @@ func (cli *JSONRPCClient) WaitForBalance( if !shouldExit { utils.Outf( "{{yellow}}waiting for %s balance: %s{{/}}\n", - utils.FormatBalance(min, consts.Decimals), + utils.FormatBalance(min), addr, ) } diff --git a/examples/morpheusvm/cmd/morpheus-cli/cmd/action.go b/examples/morpheusvm/cmd/morpheus-cli/cmd/action.go index 695849b28f..7573467b22 100644 --- a/examples/morpheusvm/cmd/morpheus-cli/cmd/action.go +++ b/examples/morpheusvm/cmd/morpheus-cli/cmd/action.go @@ -11,7 +11,6 @@ import ( "github.com/ava-labs/hypersdk/chain" "github.com/ava-labs/hypersdk/cli/prompt" "github.com/ava-labs/hypersdk/examples/morpheusvm/actions" - "github.com/ava-labs/hypersdk/examples/morpheusvm/consts" ) var actionCmd = &cobra.Command{ @@ -43,7 +42,7 @@ var transferCmd = &cobra.Command{ } // Select amount - amount, err := prompt.Amount("amount", consts.Decimals, balance, nil) + amount, err := prompt.Amount("amount", balance, nil) if err != nil { return err } diff --git a/examples/morpheusvm/cmd/morpheus-cli/cmd/handler.go b/examples/morpheusvm/cmd/morpheus-cli/cmd/handler.go index 84c8749d74..d8f957c26f 100644 --- a/examples/morpheusvm/cmd/morpheus-cli/cmd/handler.go +++ b/examples/morpheusvm/cmd/morpheus-cli/cmd/handler.go @@ -99,7 +99,7 @@ func (*Handler) GetBalance( } utils.Outf( "{{yellow}}balance:{{/}} %s %s\n", - utils.FormatBalance(balance, consts.Decimals), + utils.FormatBalance(balance), consts.Symbol, ) return balance, nil @@ -121,10 +121,6 @@ func (*Controller) Symbol() string { return consts.Symbol } -func (*Controller) Decimals() uint8 { - return consts.Decimals -} - func (*Controller) GetParser(uri string) (chain.Parser, error) { cli := vm.NewJSONRPCClient(uri) return cli.Parser(context.TODO()) diff --git a/examples/morpheusvm/cmd/morpheus-cli/cmd/resolutions.go b/examples/morpheusvm/cmd/morpheus-cli/cmd/resolutions.go index ad2e72f46f..a217a405d3 100644 --- a/examples/morpheusvm/cmd/morpheus-cli/cmd/resolutions.go +++ b/examples/morpheusvm/cmd/morpheus-cli/cmd/resolutions.go @@ -70,7 +70,7 @@ func handleTx(tx *chain.Transaction, result *chain.Result) { actor, result.Error, float64(result.Fee)/float64(tx.Base.MaxFee)*100, - utils.FormatBalance(result.Fee, consts.Decimals), + utils.FormatBalance(result.Fee), consts.Symbol, result.Units, ) @@ -81,7 +81,7 @@ func handleTx(tx *chain.Transaction, result *chain.Result) { var summaryStr string switch act := action.(type) { //nolint:gocritic case *actions.Transfer: - summaryStr = fmt.Sprintf("%s %s -> %s\n", utils.FormatBalance(act.Value, consts.Decimals), consts.Symbol, actor) + summaryStr = fmt.Sprintf("%s %s -> %s\n", utils.FormatBalance(act.Value), consts.Symbol, actor) } utils.Outf( "%s {{yellow}}%s{{/}} {{yellow}}actor:{{/}} %s {{yellow}}summary (%s):{{/}} [%s] {{yellow}}fee (max %.2f%%):{{/}} %s %s {{yellow}}consumed:{{/}} [%s]\n", @@ -91,7 +91,7 @@ func handleTx(tx *chain.Transaction, result *chain.Result) { reflect.TypeOf(action), summaryStr, float64(result.Fee)/float64(tx.Base.MaxFee)*100, - utils.FormatBalance(result.Fee, consts.Decimals), + utils.FormatBalance(result.Fee), consts.Symbol, result.Units, ) diff --git a/examples/morpheusvm/cmd/morpheus-cli/cmd/spam.go b/examples/morpheusvm/cmd/morpheus-cli/cmd/spam.go index 9ffff8626e..289c45624b 100644 --- a/examples/morpheusvm/cmd/morpheus-cli/cmd/spam.go +++ b/examples/morpheusvm/cmd/morpheus-cli/cmd/spam.go @@ -73,7 +73,7 @@ func (sh *SpamHelper) LookupBalance(choice int, address codec.Address) (uint64, "%d) {{cyan}}address:{{/}} %s {{cyan}}balance:{{/}} %s %s\n", choice, address, - utils.FormatBalance(balance, consts.Decimals), + utils.FormatBalance(balance), consts.Symbol, ) return balance, err diff --git a/examples/morpheusvm/vm/client.go b/examples/morpheusvm/vm/client.go index af51a84140..ff086c7c8f 100644 --- a/examples/morpheusvm/vm/client.go +++ b/examples/morpheusvm/vm/client.go @@ -80,7 +80,7 @@ func (cli *JSONRPCClient) WaitForBalance( if !shouldExit { utils.Outf( "{{yellow}}waiting for %s balance: %s{{/}}\n", - utils.FormatBalance(min, consts.Decimals), + utils.FormatBalance(min), addr, ) } diff --git a/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/action.go b/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/action.go index 7f5a91f7b0..3c0f1ffe0a 100644 --- a/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/action.go +++ b/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/action.go @@ -15,7 +15,6 @@ import ( "github.com/ava-labs/hypersdk/cli/prompt" "github.com/ava-labs/hypersdk/codec" "github.com/ava-labs/hypersdk/examples/vmwithcontracts/actions" - "github.com/ava-labs/hypersdk/examples/vmwithcontracts/consts" "github.com/ava-labs/hypersdk/utils" ) @@ -48,7 +47,7 @@ var transferCmd = &cobra.Command{ } // Select amount - amount, err := prompt.Amount("amount", consts.Decimals, balance, nil) + amount, err := prompt.Amount("amount", balance, nil) if err != nil { return err } @@ -127,7 +126,7 @@ var callCmd = &cobra.Command{ } // Select amount - amount, err := prompt.Amount("amount", consts.Decimals, balance, nil) + amount, err := prompt.Amount("amount", balance, nil) if err != nil { return err } @@ -174,7 +173,7 @@ var callCmd = &cobra.Command{ if err != nil { return err } - utils.Outf("%s\n", utils.FormatBalance(intValue, consts.Decimals)) + utils.Outf("%s\n", utils.FormatBalance(intValue)) } case "get_value": { diff --git a/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/handler.go b/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/handler.go index e57f4a7fa4..142ec89b00 100644 --- a/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/handler.go +++ b/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/handler.go @@ -99,7 +99,7 @@ func (*Handler) GetBalance( } utils.Outf( "{{yellow}}balance:{{/}} %s %s\n", - utils.FormatBalance(balance, consts.Decimals), + utils.FormatBalance(balance), consts.Symbol, ) return balance, nil diff --git a/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/resolutions.go b/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/resolutions.go index 202d226711..c691a0c3bf 100644 --- a/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/resolutions.go +++ b/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/resolutions.go @@ -67,7 +67,7 @@ func handleTx(tx *chain.Transaction, result *chain.Result) { actor, result.Error, float64(result.Fee)/float64(tx.Base.MaxFee)*100, - utils.FormatBalance(result.Fee, consts.Decimals), + utils.FormatBalance(result.Fee), consts.Symbol, result.Units, ) @@ -78,7 +78,7 @@ func handleTx(tx *chain.Transaction, result *chain.Result) { var summaryStr string switch act := action.(type) { //nolint:gocritic case *actions.Transfer: - summaryStr = fmt.Sprintf("%s %s -> %s\n", utils.FormatBalance(act.Value, consts.Decimals), consts.Symbol, act.To) + summaryStr = fmt.Sprintf("%s %s -> %s\n", utils.FormatBalance(act.Value), consts.Symbol, act.To) } utils.Outf( "%s {{yellow}}%s{{/}} {{yellow}}actor:{{/}} %s {{yellow}}summary (%s):{{/}} [%s] {{yellow}}fee (max %.2f%%):{{/}} %s %s {{yellow}}consumed:{{/}} [%s]\n", @@ -88,7 +88,7 @@ func handleTx(tx *chain.Transaction, result *chain.Result) { reflect.TypeOf(action), summaryStr, float64(result.Fee)/float64(tx.Base.MaxFee)*100, - utils.FormatBalance(result.Fee, consts.Decimals), + utils.FormatBalance(result.Fee), consts.Symbol, result.Units, ) diff --git a/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/spam.go b/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/spam.go index f17022a35d..4e6e53b8e2 100644 --- a/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/spam.go +++ b/examples/vmwithcontracts/cmd/vmwithcontracts-cli/cmd/spam.go @@ -73,7 +73,7 @@ func (sh *SpamHelper) LookupBalance(choice int, address codec.Address) (uint64, "%d) {{cyan}}address:{{/}} %s {{cyan}}balance:{{/}} %s %s\n", choice, address, - utils.FormatBalance(balance, consts.Decimals), + utils.FormatBalance(balance), consts.Symbol, ) return balance, err diff --git a/examples/vmwithcontracts/vm/client.go b/examples/vmwithcontracts/vm/client.go index 75ad994846..c75e8e821f 100644 --- a/examples/vmwithcontracts/vm/client.go +++ b/examples/vmwithcontracts/vm/client.go @@ -83,7 +83,7 @@ func (cli *JSONRPCClient) WaitForBalance( if !shouldExit { utils.Outf( "{{yellow}}waiting for %s balance: %s{{/}}\n", - utils.FormatBalance(min, consts.Decimals), + utils.FormatBalance(min), addr, ) } diff --git a/utils/utils.go b/utils/utils.go index 4a1e740be1..bf3c60c4de 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -65,16 +65,16 @@ func GetPort(uri string) (string, error) { return purl.Port(), err } -func FormatBalance(bal uint64, decimals uint8) string { - return strconv.FormatFloat(float64(bal)/math.Pow10(int(decimals)), 'f', int(decimals), 64) +func FormatBalance(bal uint64) string { + return strconv.FormatFloat(float64(bal)/math.Pow10(int(consts.Decimals)), 'f', int(consts.Decimals), 64) } -func ParseBalance(bal string, decimals uint8) (uint64, error) { +func ParseBalance(bal string) (uint64, error) { f, err := strconv.ParseFloat(bal, 64) if err != nil { return 0, err } - return uint64(f * math.Pow10(int(decimals))), nil + return uint64(f * math.Pow10(int(consts.Decimals))), nil } func Repeat[T any](v T, n int) []T { diff --git a/utils/utils_test.go b/utils/utils_test.go index 6c3bf14225..7a5f61d95b 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -7,6 +7,7 @@ import ( "bytes" "os" "path/filepath" + "strconv" "testing" "github.com/ava-labs/avalanchego/ids" @@ -82,3 +83,31 @@ func TestLoadBytes(t *testing.T) { // Remove _ = os.Remove(fileName) } + +func TestFormatAndParseBalance(t *testing.T) { + // this test assumes that the number of decimals is 9 + require := require.New(t) + + testCases := []struct { + input uint64 + expected string + }{ + {1000000000, "1.000000000"}, + {123456789, "0.123456789"}, + {1234567890, "1.234567890"}, + {9876543210, "9.876543210"}, + {0, "0.000000000"}, + } + + for _, tc := range testCases { + formatted := FormatBalance(tc.input) + require.Equal(tc.expected, formatted) + + parsed, err := ParseBalance(tc.expected) + require.NoError(err) + require.Equal(tc.input, parsed) + } + + _, err := ParseBalance("invalid") + require.ErrorIs(err, strconv.ErrSyntax) +}