github.com/Finschia/finschia-sdk@v0.48.1/x/bank/types/metadata.go (about)

     1  package types
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  
     8  	sdk "github.com/Finschia/finschia-sdk/types"
     9  )
    10  
    11  // Validate performs a basic validation of the coin metadata fields. It checks:
    12  //   - Name and Symbol are not blank
    13  //   - Base and Display denominations are valid coin denominations
    14  //   - Base and Display denominations are present in the DenomUnit slice
    15  //   - Base denomination has exponent 0
    16  //   - Denomination units are sorted in ascending order
    17  //   - Denomination units not duplicated
    18  func (m Metadata) Validate() error {
    19  	if strings.TrimSpace(m.Name) == "" {
    20  		return errors.New("name field cannot be blank")
    21  	}
    22  
    23  	if strings.TrimSpace(m.Symbol) == "" {
    24  		return errors.New("symbol field cannot be blank")
    25  	}
    26  
    27  	if err := sdk.ValidateDenom(m.Base); err != nil {
    28  		return fmt.Errorf("invalid metadata base denom: %w", err)
    29  	}
    30  
    31  	if err := sdk.ValidateDenom(m.Display); err != nil {
    32  		return fmt.Errorf("invalid metadata display denom: %w", err)
    33  	}
    34  
    35  	var (
    36  		hasDisplay      bool
    37  		currentExponent uint32 // check that the exponents are increasing
    38  	)
    39  
    40  	seenUnits := make(map[string]bool)
    41  
    42  	for i, denomUnit := range m.DenomUnits {
    43  		// The first denomination unit MUST be the base
    44  		if i == 0 {
    45  			// validate denomination and exponent
    46  			if denomUnit.Denom != m.Base {
    47  				return fmt.Errorf("metadata's first denomination unit must be the one with base denom '%s'", m.Base)
    48  			}
    49  			if denomUnit.Exponent != 0 {
    50  				return fmt.Errorf("the exponent for base denomination unit %s must be 0", m.Base)
    51  			}
    52  		} else if currentExponent >= denomUnit.Exponent {
    53  			return errors.New("denom units should be sorted asc by exponent")
    54  		}
    55  
    56  		currentExponent = denomUnit.Exponent
    57  
    58  		if seenUnits[denomUnit.Denom] {
    59  			return fmt.Errorf("duplicate denomination unit %s", denomUnit.Denom)
    60  		}
    61  
    62  		if denomUnit.Denom == m.Display {
    63  			hasDisplay = true
    64  		}
    65  
    66  		if err := denomUnit.Validate(); err != nil {
    67  			return err
    68  		}
    69  
    70  		seenUnits[denomUnit.Denom] = true
    71  	}
    72  
    73  	if !hasDisplay {
    74  		return fmt.Errorf("metadata must contain a denomination unit with display denom '%s'", m.Display)
    75  	}
    76  
    77  	return nil
    78  }
    79  
    80  // Validate performs a basic validation of the denomination unit fields
    81  func (du DenomUnit) Validate() error {
    82  	if err := sdk.ValidateDenom(du.Denom); err != nil {
    83  		return fmt.Errorf("invalid denom unit: %w", err)
    84  	}
    85  
    86  	seenAliases := make(map[string]bool)
    87  	for _, alias := range du.Aliases {
    88  		if seenAliases[alias] {
    89  			return fmt.Errorf("duplicate denomination unit alias %s", alias)
    90  		}
    91  
    92  		if strings.TrimSpace(alias) == "" {
    93  			return fmt.Errorf("alias for denom unit %s cannot be blank", du.Denom)
    94  		}
    95  
    96  		seenAliases[alias] = true
    97  	}
    98  
    99  	return nil
   100  }