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 }