2019-03-16 06:18:27 -07:00
|
|
|
package types
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
// denomUnits contains a mapping of denomination mapped to their respective unit
|
|
|
|
// multipliers (e.g. 1atom = 10^-6uatom).
|
|
|
|
var denomUnits = map[string]Dec{}
|
|
|
|
|
2020-11-16 03:34:54 -08:00
|
|
|
// baseDenom is the denom of smallest unit registered
|
|
|
|
var baseDenom string = ""
|
|
|
|
|
2019-03-16 06:18:27 -07:00
|
|
|
// RegisterDenom registers a denomination with a corresponding unit. If the
|
|
|
|
// denomination is already registered, an error will be returned.
|
|
|
|
func RegisterDenom(denom string, unit Dec) error {
|
2019-12-10 08:48:57 -08:00
|
|
|
if err := ValidateDenom(denom); err != nil {
|
2019-03-16 06:18:27 -07:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := denomUnits[denom]; ok {
|
|
|
|
return fmt.Errorf("denom %s already registered", denom)
|
|
|
|
}
|
|
|
|
|
|
|
|
denomUnits[denom] = unit
|
2020-11-16 03:34:54 -08:00
|
|
|
|
|
|
|
if baseDenom == "" || unit.LT(denomUnits[baseDenom]) {
|
|
|
|
baseDenom = denom
|
|
|
|
}
|
2019-03-16 06:18:27 -07:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDenomUnit returns a unit for a given denomination if it exists. A boolean
|
|
|
|
// is returned if the denomination is registered.
|
|
|
|
func GetDenomUnit(denom string) (Dec, bool) {
|
2019-12-10 08:48:57 -08:00
|
|
|
if err := ValidateDenom(denom); err != nil {
|
2019-03-16 06:18:27 -07:00
|
|
|
return ZeroDec(), false
|
|
|
|
}
|
|
|
|
|
|
|
|
unit, ok := denomUnits[denom]
|
|
|
|
if !ok {
|
|
|
|
return ZeroDec(), false
|
|
|
|
}
|
|
|
|
|
|
|
|
return unit, true
|
|
|
|
}
|
|
|
|
|
2020-11-16 03:34:54 -08:00
|
|
|
// GetBaseDenom returns the denom of smallest unit registered
|
|
|
|
func GetBaseDenom() (string, error) {
|
|
|
|
if baseDenom == "" {
|
|
|
|
return "", fmt.Errorf("no denom is registered")
|
|
|
|
}
|
|
|
|
return baseDenom, nil
|
|
|
|
}
|
|
|
|
|
2019-03-16 06:18:27 -07:00
|
|
|
// ConvertCoin attempts to convert a coin to a given denomination. If the given
|
|
|
|
// denomination is invalid or if neither denomination is registered, an error
|
|
|
|
// is returned.
|
|
|
|
func ConvertCoin(coin Coin, denom string) (Coin, error) {
|
2019-12-10 08:48:57 -08:00
|
|
|
if err := ValidateDenom(denom); err != nil {
|
2019-03-16 06:18:27 -07:00
|
|
|
return Coin{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
srcUnit, ok := GetDenomUnit(coin.Denom)
|
|
|
|
if !ok {
|
|
|
|
return Coin{}, fmt.Errorf("source denom not registered: %s", coin.Denom)
|
|
|
|
}
|
|
|
|
|
|
|
|
dstUnit, ok := GetDenomUnit(denom)
|
|
|
|
if !ok {
|
|
|
|
return Coin{}, fmt.Errorf("destination denom not registered: %s", denom)
|
|
|
|
}
|
|
|
|
|
|
|
|
if srcUnit.Equal(dstUnit) {
|
|
|
|
return NewCoin(denom, coin.Amount), nil
|
|
|
|
}
|
|
|
|
|
2020-11-16 03:34:54 -08:00
|
|
|
return NewCoin(denom, coin.Amount.ToDec().Mul(srcUnit).Quo(dstUnit).TruncateInt()), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConvertDecCoin attempts to convert a decimal coin to a given denomination. If the given
|
|
|
|
// denomination is invalid or if neither denomination is registered, an error
|
|
|
|
// is returned.
|
|
|
|
func ConvertDecCoin(coin DecCoin, denom string) (DecCoin, error) {
|
|
|
|
if err := ValidateDenom(denom); err != nil {
|
|
|
|
return DecCoin{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
srcUnit, ok := GetDenomUnit(coin.Denom)
|
|
|
|
if !ok {
|
|
|
|
return DecCoin{}, fmt.Errorf("source denom not registered: %s", coin.Denom)
|
|
|
|
}
|
|
|
|
|
|
|
|
dstUnit, ok := GetDenomUnit(denom)
|
|
|
|
if !ok {
|
|
|
|
return DecCoin{}, fmt.Errorf("destination denom not registered: %s", denom)
|
|
|
|
}
|
|
|
|
|
|
|
|
if srcUnit.Equal(dstUnit) {
|
|
|
|
return NewDecCoinFromDec(denom, coin.Amount), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewDecCoinFromDec(denom, coin.Amount.Mul(srcUnit).Quo(dstUnit)), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NormalizeCoin try to convert a coin to the smallest unit registered,
|
|
|
|
// returns original one if failed.
|
|
|
|
func NormalizeCoin(coin Coin) Coin {
|
|
|
|
base, err := GetBaseDenom()
|
|
|
|
if err != nil {
|
|
|
|
return coin
|
|
|
|
}
|
|
|
|
newCoin, err := ConvertCoin(coin, base)
|
|
|
|
if err != nil {
|
|
|
|
return coin
|
|
|
|
}
|
|
|
|
return newCoin
|
|
|
|
}
|
|
|
|
|
|
|
|
// NormalizeDecCoin try to convert a decimal coin to the smallest unit registered,
|
|
|
|
// returns original one if failed.
|
|
|
|
func NormalizeDecCoin(coin DecCoin) DecCoin {
|
|
|
|
base, err := GetBaseDenom()
|
|
|
|
if err != nil {
|
|
|
|
return coin
|
|
|
|
}
|
|
|
|
newCoin, err := ConvertDecCoin(coin, base)
|
|
|
|
if err != nil {
|
|
|
|
return coin
|
|
|
|
}
|
|
|
|
return newCoin
|
|
|
|
}
|
|
|
|
|
|
|
|
// NormalizeCoins normalize and truncate a list of decimal coins
|
|
|
|
func NormalizeCoins(coins []DecCoin) Coins {
|
|
|
|
if coins == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
result := make([]Coin, 0, len(coins))
|
|
|
|
|
|
|
|
for _, coin := range coins {
|
|
|
|
newCoin, _ := NormalizeDecCoin(coin).TruncateDecimal()
|
|
|
|
result = append(result, newCoin)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
2019-03-16 06:18:27 -07:00
|
|
|
}
|