github.com/cosmos/cosmos-sdk@v0.50.10/types/dec_coin.go (about)

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strings"
     7  
     8  	"cosmossdk.io/errors"
     9  	"cosmossdk.io/math"
    10  )
    11  
    12  // ----------------------------------------------------------------------------
    13  // Decimal Coin
    14  
    15  // NewDecCoin creates a new DecCoin instance from an Int.
    16  func NewDecCoin(denom string, amount math.Int) DecCoin {
    17  	coin := NewCoin(denom, amount)
    18  
    19  	return DecCoin{
    20  		Denom:  coin.Denom,
    21  		Amount: math.LegacyNewDecFromInt(coin.Amount),
    22  	}
    23  }
    24  
    25  // NewDecCoinFromDec creates a new DecCoin instance from a Dec.
    26  func NewDecCoinFromDec(denom string, amount math.LegacyDec) DecCoin {
    27  	mustValidateDenom(denom)
    28  
    29  	if amount.IsNegative() {
    30  		panic(fmt.Sprintf("negative decimal coin amount: %v\n", amount))
    31  	}
    32  
    33  	return DecCoin{
    34  		Denom:  denom,
    35  		Amount: amount,
    36  	}
    37  }
    38  
    39  // NewDecCoinFromCoin creates a new DecCoin from a Coin.
    40  func NewDecCoinFromCoin(coin Coin) DecCoin {
    41  	if err := coin.Validate(); err != nil {
    42  		panic(err)
    43  	}
    44  
    45  	return DecCoin{
    46  		Denom:  coin.Denom,
    47  		Amount: math.LegacyNewDecFromInt(coin.Amount),
    48  	}
    49  }
    50  
    51  // NewInt64DecCoin returns a new DecCoin with a denomination and amount. It will
    52  // panic if the amount is negative or denom is invalid.
    53  func NewInt64DecCoin(denom string, amount int64) DecCoin {
    54  	return NewDecCoin(denom, math.NewInt(amount))
    55  }
    56  
    57  // IsZero returns if the DecCoin amount is zero.
    58  func (coin DecCoin) IsZero() bool {
    59  	return coin.Amount.IsZero()
    60  }
    61  
    62  // IsGTE returns true if they are the same type and the receiver is
    63  // an equal or greater value.
    64  func (coin DecCoin) IsGTE(other DecCoin) bool {
    65  	if coin.Denom != other.Denom {
    66  		panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom))
    67  	}
    68  
    69  	return !coin.Amount.LT(other.Amount)
    70  }
    71  
    72  // IsLT returns true if they are the same type and the receiver is
    73  // a smaller value.
    74  func (coin DecCoin) IsLT(other DecCoin) bool {
    75  	if coin.Denom != other.Denom {
    76  		panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, other.Denom))
    77  	}
    78  
    79  	return coin.Amount.LT(other.Amount)
    80  }
    81  
    82  // IsEqual returns true if the two sets of Coins have the same value.
    83  // Deprecated: Use DecCoin.Equal instead.
    84  func (coin DecCoin) IsEqual(other DecCoin) bool {
    85  	return coin.Equal(other)
    86  }
    87  
    88  // Add adds amounts of two decimal coins with same denom.
    89  func (coin DecCoin) Add(coinB DecCoin) DecCoin {
    90  	if coin.Denom != coinB.Denom {
    91  		panic(fmt.Sprintf("coin denom different: %v %v\n", coin.Denom, coinB.Denom))
    92  	}
    93  	return DecCoin{coin.Denom, coin.Amount.Add(coinB.Amount)}
    94  }
    95  
    96  // Sub subtracts amounts of two decimal coins with same denom.
    97  func (coin DecCoin) Sub(coinB DecCoin) DecCoin {
    98  	if coin.Denom != coinB.Denom {
    99  		panic(fmt.Sprintf("coin denom different: %v %v\n", coin.Denom, coinB.Denom))
   100  	}
   101  	res := DecCoin{coin.Denom, coin.Amount.Sub(coinB.Amount)}
   102  	if res.IsNegative() {
   103  		panic("negative decimal coin amount")
   104  	}
   105  	return res
   106  }
   107  
   108  // TruncateDecimal returns a Coin with a truncated decimal and a DecCoin for the
   109  // change. Note, the change may be zero.
   110  func (coin DecCoin) TruncateDecimal() (Coin, DecCoin) {
   111  	truncated := coin.Amount.TruncateInt()
   112  	change := coin.Amount.Sub(math.LegacyNewDecFromInt(truncated))
   113  	return NewCoin(coin.Denom, truncated), NewDecCoinFromDec(coin.Denom, change)
   114  }
   115  
   116  // IsPositive returns true if coin amount is positive.
   117  //
   118  // TODO: Remove once unsigned integers are used.
   119  func (coin DecCoin) IsPositive() bool {
   120  	return coin.Amount.IsPositive()
   121  }
   122  
   123  // IsNegative returns true if the coin amount is negative and false otherwise.
   124  //
   125  // TODO: Remove once unsigned integers are used.
   126  func (coin DecCoin) IsNegative() bool {
   127  	return coin.Amount.IsNegative()
   128  }
   129  
   130  // String implements the Stringer interface for DecCoin. It returns a
   131  // human-readable representation of a decimal coin.
   132  func (coin DecCoin) String() string {
   133  	return fmt.Sprintf("%v%v", coin.Amount, coin.Denom)
   134  }
   135  
   136  // Validate returns an error if the DecCoin has a negative amount or if the denom is invalid.
   137  func (coin DecCoin) Validate() error {
   138  	if err := ValidateDenom(coin.Denom); err != nil {
   139  		return err
   140  	}
   141  	if coin.IsNegative() {
   142  		return fmt.Errorf("decimal coin %s amount cannot be negative", coin)
   143  	}
   144  	return nil
   145  }
   146  
   147  // IsValid returns true if the DecCoin has a non-negative amount and the denom is valid.
   148  func (coin DecCoin) IsValid() bool {
   149  	return coin.Validate() == nil
   150  }
   151  
   152  // ----------------------------------------------------------------------------
   153  // Decimal Coins
   154  
   155  // DecCoins defines a slice of coins with decimal values
   156  type DecCoins []DecCoin
   157  
   158  // NewDecCoins constructs a new coin set with with decimal values
   159  // from DecCoins. The provided coins will be sanitized by removing
   160  // zero coins and sorting the coin set. A panic will occur if the coin set is not valid.
   161  func NewDecCoins(decCoins ...DecCoin) DecCoins {
   162  	newDecCoins := sanitizeDecCoins(decCoins)
   163  	if err := newDecCoins.Validate(); err != nil {
   164  		panic(fmt.Errorf("invalid coin set %s: %w", newDecCoins, err))
   165  	}
   166  
   167  	return newDecCoins
   168  }
   169  
   170  func sanitizeDecCoins(decCoins []DecCoin) DecCoins {
   171  	// remove zeroes
   172  	newDecCoins := removeZeroDecCoins(decCoins)
   173  	if len(newDecCoins) == 0 {
   174  		return DecCoins{}
   175  	}
   176  
   177  	return newDecCoins.Sort()
   178  }
   179  
   180  // NewDecCoinsFromCoins constructs a new coin set with decimal values
   181  // from regular Coins.
   182  func NewDecCoinsFromCoins(coins ...Coin) DecCoins {
   183  	if len(coins) == 0 {
   184  		return DecCoins{}
   185  	}
   186  
   187  	decCoins := make([]DecCoin, 0, len(coins))
   188  	newCoins := NewCoins(coins...)
   189  	for _, coin := range newCoins {
   190  		decCoins = append(decCoins, NewDecCoinFromCoin(coin))
   191  	}
   192  
   193  	return decCoins
   194  }
   195  
   196  // String implements the Stringer interface for DecCoins. It returns a
   197  // human-readable representation of decimal coins.
   198  func (coins DecCoins) String() string {
   199  	if len(coins) == 0 {
   200  		return ""
   201  	}
   202  
   203  	out := ""
   204  	for _, coin := range coins {
   205  		out += fmt.Sprintf("%v,", coin.String())
   206  	}
   207  
   208  	return out[:len(out)-1]
   209  }
   210  
   211  // TruncateDecimal returns the coins with truncated decimals and returns the
   212  // change. Note, it will not return any zero-amount coins in either the truncated or
   213  // change coins.
   214  func (coins DecCoins) TruncateDecimal() (truncatedCoins Coins, changeCoins DecCoins) {
   215  	for _, coin := range coins {
   216  		truncated, change := coin.TruncateDecimal()
   217  		if !truncated.IsZero() {
   218  			truncatedCoins = truncatedCoins.Add(truncated)
   219  		}
   220  		if !change.IsZero() {
   221  			changeCoins = changeCoins.Add(change)
   222  		}
   223  	}
   224  
   225  	return truncatedCoins, changeCoins
   226  }
   227  
   228  // Add adds two sets of DecCoins.
   229  //
   230  // NOTE: Add operates under the invariant that coins are sorted by
   231  // denominations.
   232  //
   233  // CONTRACT: Add will never return Coins where one Coin has a non-positive
   234  // amount. In otherwords, IsValid will always return true.
   235  func (coins DecCoins) Add(coinsB ...DecCoin) DecCoins {
   236  	return coins.safeAdd(coinsB)
   237  }
   238  
   239  // safeAdd will perform addition of two DecCoins sets. If both coin sets are
   240  // empty, then an empty set is returned. If only a single set is empty, the
   241  // other set is returned. Otherwise, the coins are compared in order of their
   242  // denomination and addition only occurs when the denominations match, otherwise
   243  // the coin is simply added to the sum assuming it's not zero.
   244  func (coins DecCoins) safeAdd(coinsB DecCoins) DecCoins {
   245  	sum := ([]DecCoin)(nil)
   246  	indexA, indexB := 0, 0
   247  	lenA, lenB := len(coins), len(coinsB)
   248  
   249  	for {
   250  		if indexA == lenA {
   251  			if indexB == lenB {
   252  				// return nil coins if both sets are empty
   253  				return sum
   254  			}
   255  
   256  			// return set B (excluding zero coins) if set A is empty
   257  			return append(sum, removeZeroDecCoins(coinsB[indexB:])...)
   258  		} else if indexB == lenB {
   259  			// return set A (excluding zero coins) if set B is empty
   260  			return append(sum, removeZeroDecCoins(coins[indexA:])...)
   261  		}
   262  
   263  		coinA, coinB := coins[indexA], coinsB[indexB]
   264  
   265  		switch strings.Compare(coinA.Denom, coinB.Denom) {
   266  		case -1: // coin A denom < coin B denom
   267  			if !coinA.IsZero() {
   268  				sum = append(sum, coinA)
   269  			}
   270  
   271  			indexA++
   272  
   273  		case 0: // coin A denom == coin B denom
   274  			res := coinA.Add(coinB)
   275  			if !res.IsZero() {
   276  				sum = append(sum, res)
   277  			}
   278  
   279  			indexA++
   280  			indexB++
   281  
   282  		case 1: // coin A denom > coin B denom
   283  			if !coinB.IsZero() {
   284  				sum = append(sum, coinB)
   285  			}
   286  
   287  			indexB++
   288  		}
   289  	}
   290  }
   291  
   292  // negative returns a set of coins with all amount negative.
   293  func (coins DecCoins) negative() DecCoins {
   294  	res := make([]DecCoin, 0, len(coins))
   295  	for _, coin := range coins {
   296  		res = append(res, DecCoin{
   297  			Denom:  coin.Denom,
   298  			Amount: coin.Amount.Neg(),
   299  		})
   300  	}
   301  	return res
   302  }
   303  
   304  // Sub subtracts a set of DecCoins from another (adds the inverse).
   305  func (coins DecCoins) Sub(coinsB DecCoins) DecCoins {
   306  	diff, hasNeg := coins.SafeSub(coinsB)
   307  	if hasNeg {
   308  		panic("negative coin amount")
   309  	}
   310  
   311  	return diff
   312  }
   313  
   314  // SafeSub performs the same arithmetic as Sub but returns a boolean if any
   315  // negative coin amount was returned.
   316  func (coins DecCoins) SafeSub(coinsB DecCoins) (DecCoins, bool) {
   317  	diff := coins.safeAdd(coinsB.negative())
   318  	return diff, diff.IsAnyNegative()
   319  }
   320  
   321  // Intersect will return a new set of coins which contains the minimum DecCoin
   322  // for common denoms found in both `coins` and `coinsB`. For denoms not common
   323  // to both `coins` and `coinsB` the minimum is considered to be 0, thus they
   324  // are not added to the final set. In other words, trim any denom amount from
   325  // coin which exceeds that of coinB, such that (coin.Intersect(coinB)).IsLTE(coinB).
   326  // See also Coins.Min().
   327  func (coins DecCoins) Intersect(coinsB DecCoins) DecCoins {
   328  	res := make([]DecCoin, len(coins))
   329  	for i, coin := range coins {
   330  		minCoin := DecCoin{
   331  			Denom:  coin.Denom,
   332  			Amount: math.LegacyMinDec(coin.Amount, coinsB.AmountOf(coin.Denom)),
   333  		}
   334  		res[i] = minCoin
   335  	}
   336  	return removeZeroDecCoins(res)
   337  }
   338  
   339  // GetDenomByIndex returns the Denom to make the findDup generic
   340  func (coins DecCoins) GetDenomByIndex(i int) string {
   341  	return coins[i].Denom
   342  }
   343  
   344  // IsAnyNegative returns true if there is at least one coin whose amount
   345  // is negative; returns false otherwise. It returns false if the DecCoins set
   346  // is empty too.
   347  //
   348  // TODO: Remove once unsigned integers are used.
   349  func (coins DecCoins) IsAnyNegative() bool {
   350  	for _, coin := range coins {
   351  		if coin.IsNegative() {
   352  			return true
   353  		}
   354  	}
   355  
   356  	return false
   357  }
   358  
   359  // MulDec multiplies all the coins by a decimal.
   360  //
   361  // CONTRACT: No zero coins will be returned.
   362  func (coins DecCoins) MulDec(d math.LegacyDec) DecCoins {
   363  	var res DecCoins
   364  	for _, coin := range coins {
   365  		product := DecCoin{
   366  			Denom:  coin.Denom,
   367  			Amount: coin.Amount.Mul(d),
   368  		}
   369  
   370  		if !product.IsZero() {
   371  			res = res.Add(product)
   372  		}
   373  	}
   374  
   375  	return res
   376  }
   377  
   378  // MulDecTruncate multiplies all the decimal coins by a decimal, truncating. It
   379  // returns nil DecCoins if d is zero.
   380  //
   381  // CONTRACT: No zero coins will be returned.
   382  func (coins DecCoins) MulDecTruncate(d math.LegacyDec) DecCoins {
   383  	if d.IsZero() {
   384  		return DecCoins{}
   385  	}
   386  
   387  	var res DecCoins
   388  	for _, coin := range coins {
   389  		product := DecCoin{
   390  			Denom:  coin.Denom,
   391  			Amount: coin.Amount.MulTruncate(d),
   392  		}
   393  
   394  		if !product.IsZero() {
   395  			res = res.Add(product)
   396  		}
   397  	}
   398  
   399  	return res
   400  }
   401  
   402  // QuoDec divides all the decimal coins by a decimal. It panics if d is zero.
   403  //
   404  // CONTRACT: No zero coins will be returned.
   405  func (coins DecCoins) QuoDec(d math.LegacyDec) DecCoins {
   406  	if d.IsZero() {
   407  		panic("invalid zero decimal")
   408  	}
   409  
   410  	var res DecCoins
   411  	for _, coin := range coins {
   412  		quotient := DecCoin{
   413  			Denom:  coin.Denom,
   414  			Amount: coin.Amount.Quo(d),
   415  		}
   416  
   417  		if !quotient.IsZero() {
   418  			res = res.Add(quotient)
   419  		}
   420  	}
   421  
   422  	return res
   423  }
   424  
   425  // QuoDecTruncate divides all the decimal coins by a decimal, truncating. It
   426  // panics if d is zero.
   427  //
   428  // CONTRACT: No zero coins will be returned.
   429  func (coins DecCoins) QuoDecTruncate(d math.LegacyDec) DecCoins {
   430  	if d.IsZero() {
   431  		panic("invalid zero decimal")
   432  	}
   433  
   434  	var res DecCoins
   435  	for _, coin := range coins {
   436  		quotient := DecCoin{
   437  			Denom:  coin.Denom,
   438  			Amount: coin.Amount.QuoTruncate(d),
   439  		}
   440  
   441  		if !quotient.IsZero() {
   442  			res = res.Add(quotient)
   443  		}
   444  	}
   445  
   446  	return res
   447  }
   448  
   449  // Empty returns true if there are no coins and false otherwise.
   450  func (coins DecCoins) Empty() bool {
   451  	return len(coins) == 0
   452  }
   453  
   454  // AmountOf returns the amount of a denom from deccoins
   455  func (coins DecCoins) AmountOf(denom string) math.LegacyDec {
   456  	mustValidateDenom(denom)
   457  
   458  	switch len(coins) {
   459  	case 0:
   460  		return math.LegacyZeroDec()
   461  
   462  	case 1:
   463  		coin := coins[0]
   464  		if coin.Denom == denom {
   465  			return coin.Amount
   466  		}
   467  		return math.LegacyZeroDec()
   468  
   469  	default:
   470  		midIdx := len(coins) / 2 // 2:1, 3:1, 4:2
   471  		coin := coins[midIdx]
   472  
   473  		switch {
   474  		case denom < coin.Denom:
   475  			return coins[:midIdx].AmountOf(denom)
   476  		case denom == coin.Denom:
   477  			return coin.Amount
   478  		default:
   479  			return coins[midIdx+1:].AmountOf(denom)
   480  		}
   481  	}
   482  }
   483  
   484  // Equal returns true if the two sets of DecCoins have the same value.
   485  func (coins DecCoins) Equal(coinsB DecCoins) bool {
   486  	if len(coins) != len(coinsB) {
   487  		return false
   488  	}
   489  
   490  	coins = coins.Sort()
   491  	coinsB = coinsB.Sort()
   492  
   493  	for i := 0; i < len(coins); i++ {
   494  		if !coins[i].Equal(coinsB[i]) {
   495  			return false
   496  		}
   497  	}
   498  
   499  	return true
   500  }
   501  
   502  // IsZero returns whether all coins are zero
   503  func (coins DecCoins) IsZero() bool {
   504  	for _, coin := range coins {
   505  		if !coin.Amount.IsZero() {
   506  			return false
   507  		}
   508  	}
   509  	return true
   510  }
   511  
   512  // Validate checks that the DecCoins are sorted, have positive amount, with a valid and unique
   513  // denomination (i.e no duplicates). Otherwise, it returns an error.
   514  func (coins DecCoins) Validate() error {
   515  	switch len(coins) {
   516  	case 0:
   517  		return nil
   518  
   519  	case 1:
   520  		if err := ValidateDenom(coins[0].Denom); err != nil {
   521  			return err
   522  		}
   523  		if !coins[0].IsPositive() {
   524  			return fmt.Errorf("coin %s amount is not positive", coins[0])
   525  		}
   526  		return nil
   527  	default:
   528  		// check single coin case
   529  		if err := (DecCoins{coins[0]}).Validate(); err != nil {
   530  			return err
   531  		}
   532  
   533  		lowDenom := coins[0].Denom
   534  		seenDenoms := make(map[string]bool)
   535  		seenDenoms[lowDenom] = true
   536  
   537  		for _, coin := range coins[1:] {
   538  			if seenDenoms[coin.Denom] {
   539  				return fmt.Errorf("duplicate denomination %s", coin.Denom)
   540  			}
   541  			if err := ValidateDenom(coin.Denom); err != nil {
   542  				return err
   543  			}
   544  			if coin.Denom <= lowDenom {
   545  				return fmt.Errorf("denomination %s is not sorted", coin.Denom)
   546  			}
   547  			if !coin.IsPositive() {
   548  				return fmt.Errorf("coin %s amount is not positive", coin.Denom)
   549  			}
   550  
   551  			// we compare each coin against the last denom
   552  			lowDenom = coin.Denom
   553  			seenDenoms[coin.Denom] = true
   554  		}
   555  
   556  		return nil
   557  	}
   558  }
   559  
   560  // IsValid calls Validate and returns true when the DecCoins are sorted, have positive amount, with a
   561  // valid and unique denomination (i.e no duplicates).
   562  func (coins DecCoins) IsValid() bool {
   563  	return coins.Validate() == nil
   564  }
   565  
   566  // IsAllPositive returns true if there is at least one coin and all currencies
   567  // have a positive value.
   568  //
   569  // TODO: Remove once unsigned integers are used.
   570  func (coins DecCoins) IsAllPositive() bool {
   571  	if len(coins) == 0 {
   572  		return false
   573  	}
   574  
   575  	for _, coin := range coins {
   576  		if !coin.IsPositive() {
   577  			return false
   578  		}
   579  	}
   580  
   581  	return true
   582  }
   583  
   584  func removeZeroDecCoins(coins DecCoins) DecCoins {
   585  	result := make([]DecCoin, 0, len(coins))
   586  
   587  	for _, coin := range coins {
   588  		if !coin.IsZero() {
   589  			result = append(result, coin)
   590  		}
   591  	}
   592  
   593  	return result
   594  }
   595  
   596  //-----------------------------------------------------------------------------
   597  // Sorting
   598  
   599  var _ sort.Interface = DecCoins{}
   600  
   601  // Len implements sort.Interface for DecCoins
   602  func (coins DecCoins) Len() int { return len(coins) }
   603  
   604  // Less implements sort.Interface for DecCoins
   605  func (coins DecCoins) Less(i, j int) bool { return coins[i].Denom < coins[j].Denom }
   606  
   607  // Swap implements sort.Interface for DecCoins
   608  func (coins DecCoins) Swap(i, j int) { coins[i], coins[j] = coins[j], coins[i] }
   609  
   610  // Sort is a helper function to sort the set of decimal coins in-place.
   611  func (coins DecCoins) Sort() DecCoins {
   612  	// sort.Sort(coins) does a costly runtime copy as part of `runtime.convTSlice`
   613  	// So we avoid this heap allocation if len(coins) <= 1. In the future, we should hopefully find
   614  	// a strategy to always avoid this.
   615  	if len(coins) > 1 {
   616  		sort.Sort(coins)
   617  	}
   618  	return coins
   619  }
   620  
   621  // ----------------------------------------------------------------------------
   622  // Parsing
   623  
   624  // ParseDecCoin parses a decimal coin from a string, returning an error if
   625  // invalid. An empty string is considered invalid.
   626  func ParseDecCoin(coinStr string) (coin DecCoin, err error) {
   627  	coinStr = strings.TrimSpace(coinStr)
   628  
   629  	matches := reDecCoin.FindStringSubmatch(coinStr)
   630  	if matches == nil {
   631  		return DecCoin{}, fmt.Errorf("invalid decimal coin expression: %s", coinStr)
   632  	}
   633  
   634  	amountStr, denomStr := matches[1], matches[2]
   635  
   636  	amount, err := math.LegacyNewDecFromStr(amountStr)
   637  	if err != nil {
   638  		return DecCoin{}, errors.Wrap(err, fmt.Sprintf("failed to parse decimal coin amount: %s", amountStr))
   639  	}
   640  
   641  	if err := ValidateDenom(denomStr); err != nil {
   642  		return DecCoin{}, fmt.Errorf("invalid denom cannot contain spaces: %s", err)
   643  	}
   644  
   645  	return NewDecCoinFromDec(denomStr, amount), nil
   646  }
   647  
   648  // ParseDecCoins will parse out a list of decimal coins separated by commas. If the parsing is successuful,
   649  // the provided coins will be sanitized by removing zero coins and sorting the coin set. Lastly
   650  // a validation of the coin set is executed. If the check passes, ParseDecCoins will return the sanitized coins.
   651  // Otherwise it will return an error.
   652  // If an empty string is provided to ParseDecCoins, it returns nil Coins.
   653  // Expected format: "{amount0}{denomination},...,{amountN}{denominationN}"
   654  func ParseDecCoins(coinsStr string) (DecCoins, error) {
   655  	coinsStr = strings.TrimSpace(coinsStr)
   656  	if len(coinsStr) == 0 {
   657  		return nil, nil
   658  	}
   659  
   660  	coinStrs := strings.Split(coinsStr, ",")
   661  	decCoins := make(DecCoins, len(coinStrs))
   662  	for i, coinStr := range coinStrs {
   663  		coin, err := ParseDecCoin(coinStr)
   664  		if err != nil {
   665  			return nil, err
   666  		}
   667  
   668  		decCoins[i] = coin
   669  	}
   670  
   671  	newDecCoins := sanitizeDecCoins(decCoins)
   672  	if err := newDecCoins.Validate(); err != nil {
   673  		return nil, err
   674  	}
   675  
   676  	return newDecCoins, nil
   677  }