diff --git a/types/bench_test.go b/types/bench_test.go index be7e0c7f4b..6c1cbc88cb 100644 --- a/types/bench_test.go +++ b/types/bench_test.go @@ -18,7 +18,7 @@ func BenchmarkParseCoin(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { for _, coinStr := range coinStrs { - coin, err := types.ParseCoin(coinStr) + coin, err := types.ParseCoinNormalized(coinStr) if err != nil { b.Fatal(err) } diff --git a/types/coin.go b/types/coin.go index da2e3c398a..b86cff5186 100644 --- a/types/coin.go +++ b/types/coin.go @@ -599,11 +599,9 @@ var ( // Denominations can be 3 ~ 128 characters long and support letters, followed by either // a letter, a number or a separator ('/'). reDnmString = `[a-zA-Z][a-zA-Z0-9/]{2,127}` - reAmt = `[[:digit:]]+` reDecAmt = `[[:digit:]]+(?:\.[[:digit:]]+)?|\.[[:digit:]]+` reSpc = `[[:space:]]*` reDnm *regexp.Regexp - reCoin *regexp.Regexp reDecCoin *regexp.Regexp ) @@ -625,7 +623,6 @@ func SetCoinDenomRegex(reFn func() string) { coinDenomRegex = reFn reDnm = regexp.MustCompile(fmt.Sprintf(`^%s$`, coinDenomRegex())) - reCoin = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, reAmt, reSpc, coinDenomRegex())) reDecCoin = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, reDecAmt, reSpc, coinDenomRegex())) } @@ -643,29 +640,17 @@ func mustValidateDenom(denom string) { } } -// ParseCoin parses a cli input for one coin type, returning errors if invalid or on an empty string +// ParseCoinNormalized parses and normalize a cli input for one coin type, returning errors if invalid or on an empty string // as well. // Expected format: "{amount}{denomination}" -func ParseCoin(coinStr string) (coin Coin, err error) { - coinStr = strings.TrimSpace(coinStr) - - matches := reCoin.FindStringSubmatch(coinStr) - if matches == nil { - return Coin{}, fmt.Errorf("invalid coin expression: %s", coinStr) - } - - denomStr, amountStr := matches[2], matches[1] - - amount, ok := NewIntFromString(amountStr) - if !ok { - return Coin{}, fmt.Errorf("failed to parse coin amount: %s", amountStr) - } - - if err := ValidateDenom(denomStr); err != nil { +func ParseCoinNormalized(coinStr string) (coin Coin, err error) { + decCoin, err := ParseDecCoin(coinStr) + if err != nil { return Coin{}, err } - return NewCoin(denomStr, amount), nil + coin, _ = NormalizeDecCoin(decCoin).TruncateDecimal() + return coin, nil } // ParseCoinsNormalized will parse out a list of coins separated by commas, and normalize them by converting to smallest diff --git a/x/ibc/applications/transfer/client/cli/tx.go b/x/ibc/applications/transfer/client/cli/tx.go index 1c4fa4e613..507840a582 100644 --- a/x/ibc/applications/transfer/client/cli/tx.go +++ b/x/ibc/applications/transfer/client/cli/tx.go @@ -46,7 +46,7 @@ to the counterparty channel. Any timeout set to 0 is disabled.`), srcChannel := args[1] receiver := args[2] - coin, err := sdk.ParseCoin(args[3]) + coin, err := sdk.ParseCoinNormalized(args[3]) if err != nil { return err } diff --git a/x/staking/client/cli/cli_test.go b/x/staking/client/cli/cli_test.go index 12b4084a4e..40c051bf25 100644 --- a/x/staking/client/cli/cli_test.go +++ b/x/staking/client/cli/cli_test.go @@ -51,7 +51,7 @@ func (s *IntegrationTestSuite) SetupSuite() { _, err := s.network.WaitForHeight(1) s.Require().NoError(err) - unbond, err := sdk.ParseCoin("10stake") + unbond, err := sdk.ParseCoinNormalized("10stake") s.Require().NoError(err) val := s.network.Validators[0] diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index 45bc2f8abc..72938ce0a0 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -172,7 +172,7 @@ $ %s tx staking delegate %s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 1000stake --f return err } - amount, err := sdk.ParseCoin(args[1]) + amount, err := sdk.ParseCoinNormalized(args[1]) if err != nil { return err } @@ -231,7 +231,7 @@ $ %s tx staking redelegate %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj %s1l2rsakp3 return err } - amount, err := sdk.ParseCoin(args[2]) + amount, err := sdk.ParseCoinNormalized(args[2]) if err != nil { return err } @@ -279,7 +279,7 @@ $ %s tx staking unbond %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from return err } - amount, err := sdk.ParseCoin(args[1]) + amount, err := sdk.ParseCoinNormalized(args[1]) if err != nil { return err } @@ -300,7 +300,7 @@ $ %s tx staking unbond %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from func NewBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *flag.FlagSet) (tx.Factory, sdk.Msg, error) { fAmount, _ := fs.GetString(FlagAmount) - amount, err := sdk.ParseCoin(fAmount) + amount, err := sdk.ParseCoinNormalized(fAmount) if err != nil { return txf, nil, err } @@ -514,7 +514,7 @@ func PrepareConfigForTxCreateValidator(flagSet *flag.FlagSet, moniker, nodeID, c // BuildCreateValidatorMsg makes a new MsgCreateValidator. func BuildCreateValidatorMsg(clientCtx client.Context, config TxCreateValidatorConfig, txBldr tx.Factory, generateOnly bool) (tx.Factory, sdk.Msg, error) { amounstStr := config.Amount - amount, err := sdk.ParseCoin(amounstStr) + amount, err := sdk.ParseCoinNormalized(amounstStr) if err != nil { return txBldr, nil, err diff --git a/x/staking/client/rest/grpc_query_test.go b/x/staking/client/rest/grpc_query_test.go index 3aa4afdcfe..696a55ff9b 100644 --- a/x/staking/client/rest/grpc_query_test.go +++ b/x/staking/client/rest/grpc_query_test.go @@ -39,7 +39,7 @@ func (s *IntegrationTestSuite) SetupSuite() { _, err := s.network.WaitForHeight(1) s.Require().NoError(err) - unbond, err := sdk.ParseCoin("10stake") + unbond, err := sdk.ParseCoinNormalized("10stake") s.Require().NoError(err) val := s.network.Validators[0]