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 }