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  }