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