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

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"cosmossdk.io/math"
     7  )
     8  
     9  // denomUnits contains a mapping of denomination mapped to their respective unit
    10  // multipliers (e.g. 1atom = 10^-6uatom).
    11  var denomUnits = map[string]math.LegacyDec{}
    12  
    13  // baseDenom is the denom of smallest unit registered
    14  var baseDenom string
    15  
    16  // RegisterDenom registers a denomination with a corresponding unit. If the
    17  // denomination is already registered, an error will be returned.
    18  func RegisterDenom(denom string, unit math.LegacyDec) error {
    19  	if err := ValidateDenom(denom); err != nil {
    20  		return err
    21  	}
    22  
    23  	if _, ok := denomUnits[denom]; ok {
    24  		return fmt.Errorf("denom %s already registered", denom)
    25  	}
    26  
    27  	denomUnits[denom] = unit
    28  
    29  	if baseDenom == "" || unit.LT(denomUnits[baseDenom]) {
    30  		baseDenom = denom
    31  	}
    32  	return nil
    33  }
    34  
    35  // GetDenomUnit returns a unit for a given denomination if it exists. A boolean
    36  // is returned if the denomination is registered.
    37  func GetDenomUnit(denom string) (math.LegacyDec, bool) {
    38  	if err := ValidateDenom(denom); err != nil {
    39  		return math.LegacyZeroDec(), false
    40  	}
    41  
    42  	unit, ok := denomUnits[denom]
    43  	if !ok {
    44  		return math.LegacyZeroDec(), false
    45  	}
    46  
    47  	return unit, true
    48  }
    49  
    50  // SetBaseDenom allow overwritting the base denom
    51  // if the denom has registered before, otherwise return error
    52  func SetBaseDenom(denom string) error {
    53  	_, ok := denomUnits[denom]
    54  	if !ok {
    55  		return fmt.Errorf("denom %s not registered", denom)
    56  	}
    57  	baseDenom = denom
    58  	return nil
    59  }
    60  
    61  // GetBaseDenom returns the denom of smallest unit registered
    62  func GetBaseDenom() (string, error) {
    63  	if baseDenom == "" {
    64  		return "", fmt.Errorf("no denom is registered")
    65  	}
    66  	return baseDenom, nil
    67  }
    68  
    69  // ConvertCoin attempts to convert a coin to a given denomination. If the given
    70  // denomination is invalid or if neither denomination is registered, an error
    71  // is returned.
    72  func ConvertCoin(coin Coin, denom string) (Coin, error) {
    73  	if err := ValidateDenom(denom); err != nil {
    74  		return Coin{}, err
    75  	}
    76  
    77  	srcUnit, ok := GetDenomUnit(coin.Denom)
    78  	if !ok {
    79  		return Coin{}, fmt.Errorf("source denom not registered: %s", coin.Denom)
    80  	}
    81  
    82  	dstUnit, ok := GetDenomUnit(denom)
    83  	if !ok {
    84  		return Coin{}, fmt.Errorf("destination denom not registered: %s", denom)
    85  	}
    86  
    87  	if srcUnit.Equal(dstUnit) {
    88  		return NewCoin(denom, coin.Amount), nil
    89  	}
    90  
    91  	return NewCoin(denom, math.LegacyNewDecFromInt(coin.Amount).Mul(srcUnit).Quo(dstUnit).TruncateInt()), nil
    92  }
    93  
    94  // ConvertDecCoin attempts to convert a decimal coin to a given denomination. If the given
    95  // denomination is invalid or if neither denomination is registered, an error
    96  // is returned.
    97  func ConvertDecCoin(coin DecCoin, denom string) (DecCoin, error) {
    98  	if err := ValidateDenom(denom); err != nil {
    99  		return DecCoin{}, err
   100  	}
   101  
   102  	srcUnit, ok := GetDenomUnit(coin.Denom)
   103  	if !ok {
   104  		return DecCoin{}, fmt.Errorf("source denom not registered: %s", coin.Denom)
   105  	}
   106  
   107  	dstUnit, ok := GetDenomUnit(denom)
   108  	if !ok {
   109  		return DecCoin{}, fmt.Errorf("destination denom not registered: %s", denom)
   110  	}
   111  
   112  	if srcUnit.Equal(dstUnit) {
   113  		return NewDecCoinFromDec(denom, coin.Amount), nil
   114  	}
   115  
   116  	return NewDecCoinFromDec(denom, coin.Amount.Mul(srcUnit).Quo(dstUnit)), nil
   117  }
   118  
   119  // NormalizeCoin try to convert a coin to the smallest unit registered,
   120  // returns original one if failed.
   121  func NormalizeCoin(coin Coin) Coin {
   122  	base, err := GetBaseDenom()
   123  	if err != nil {
   124  		return coin
   125  	}
   126  	newCoin, err := ConvertCoin(coin, base)
   127  	if err != nil {
   128  		return coin
   129  	}
   130  	return newCoin
   131  }
   132  
   133  // NormalizeDecCoin try to convert a decimal coin to the smallest unit registered,
   134  // returns original one if failed.
   135  func NormalizeDecCoin(coin DecCoin) DecCoin {
   136  	base, err := GetBaseDenom()
   137  	if err != nil {
   138  		return coin
   139  	}
   140  	newCoin, err := ConvertDecCoin(coin, base)
   141  	if err != nil {
   142  		return coin
   143  	}
   144  	return newCoin
   145  }
   146  
   147  // NormalizeCoins normalize and truncate a list of decimal coins
   148  func NormalizeCoins(coins []DecCoin) Coins {
   149  	if coins == nil {
   150  		return nil
   151  	}
   152  	result := make([]Coin, 0, len(coins))
   153  
   154  	for _, coin := range coins {
   155  		newCoin, _ := NormalizeDecCoin(coin).TruncateDecimal()
   156  		result = append(result, newCoin)
   157  	}
   158  
   159  	return result
   160  }