diff --git a/x/asset/nft/types/token.go b/x/asset/nft/types/token.go index 0989cfb12..76c0dc16d 100644 --- a/x/asset/nft/types/token.go +++ b/x/asset/nft/types/token.go @@ -17,10 +17,10 @@ var ( // since the class id has {symbol}-{address} format and // the address length might be up to 66 symbols and the demon length must be less than 101 // this leaves room for 33 characters, but we round it down to 30 to be conservative. - nftSymbolRegexStr = `^[a-zA-Z][a-zA-Z0-9]{0,30}$` + nftSymbolRegexStr = `^[a-zA-Z][a-zA-Z0-9/:._]{0,30}$` nftSymbolRegex = regexp.MustCompile(nftSymbolRegexStr) // the regexp is same as for the nft module. - nftIDRegexStr = `^[a-zA-Z][a-zA-Z0-9/:-]{2,100}$` + nftIDRegexStr = `^[a-zA-Z][a-zA-Z0-9/:._-]{2,100}$` nftIDRegex = regexp.MustCompile(nftIDRegexStr) nftClassIDSeparator = "-" diff --git a/x/asset/nft/types/token_test.go b/x/asset/nft/types/token_test.go index b71c0f642..55fc9c26f 100644 --- a/x/asset/nft/types/token_test.go +++ b/x/asset/nft/types/token_test.go @@ -13,6 +13,89 @@ import ( "github.com/CoreumFoundation/coreum/v3/x/asset/nft/types" ) +func TestSymbolAndIDValidation(t *testing.T) { + testCases := []struct { + name string + value string + validSymbol bool + validID bool + }{ + { + name: "containing dash", + value: "ABC-1", + validSymbol: false, + validID: true, + }, + { + name: "containing dot and upper case", + value: "ABC.1", + validSymbol: true, + validID: true, + }, + { + name: "containing dot", + value: "abc.1", + validSymbol: true, + validID: true, + }, + { + name: "containing colon", + value: "ABC:1", + validSymbol: true, + validID: true, + }, + { + name: "similar to ft denom", + value: "btc-devcore1phjrez5j2wp5qzp0zvlqavasvw60mkp2zmfe6h", + validSymbol: false, + validID: true, + }, + { + name: "just core", + value: "core", + validSymbol: true, + validID: true, + }, + { + name: "31 chars", + value: "A123456789012345678901234567890", + validSymbol: true, + validID: true, + }, + { + name: "32 chars", + value: "A1234567890123456789012345678901", + validSymbol: false, + validID: true, + }, + { + name: "start with number", + value: "3abc", + validSymbol: false, + validID: false, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + err := types.ValidateClassSymbol(tc.value) + if tc.validSymbol { + require.NoError(t, err, "expected no error for symbol %s", tc.value) + } else { + require.Error(t, err, "expected error for symbol %s", tc.value) + } + + err = types.ValidateTokenID(tc.value) + if tc.validID { + require.NoError(t, err, "expected no error for nft id %s", tc.value) + } else { + require.Error(t, err, "expected error for nft id %s", tc.value) + } + }) + } +} + func TestFTDefinition_CheckFeatureAllowed(t *testing.T) { issuer := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) nonIssuer := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())