github.com/InjectiveLabs/sdk-go@v1.53.0/typeddata/typed_data.go (about)

     1  package typeddata
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math/big"
     7  	"reflect"
     8  	"regexp"
     9  	"sort"
    10  	"strconv"
    11  	"strings"
    12  	"unicode"
    13  	"unicode/utf8"
    14  
    15  	"github.com/ethereum/go-ethereum/accounts"
    16  	"github.com/ethereum/go-ethereum/common"
    17  	"github.com/ethereum/go-ethereum/common/hexutil"
    18  	"github.com/ethereum/go-ethereum/common/math"
    19  	"github.com/ethereum/go-ethereum/crypto"
    20  	"github.com/pkg/errors"
    21  )
    22  
    23  type SigFormat struct {
    24  	Mime        string
    25  	ByteVersion byte
    26  }
    27  
    28  var (
    29  	IntendedValidator = SigFormat{
    30  		accounts.MimetypeDataWithValidator,
    31  		0x00,
    32  	}
    33  	DataTyped = SigFormat{
    34  		accounts.MimetypeTypedData,
    35  		0x01,
    36  	}
    37  	ApplicationClique = SigFormat{
    38  		accounts.MimetypeClique,
    39  		0x02,
    40  	}
    41  	TextPlain = SigFormat{
    42  		accounts.MimetypeTextPlain,
    43  		0x45,
    44  	}
    45  )
    46  
    47  type ValidatorData struct {
    48  	Address common.Address
    49  	Message hexutil.Bytes
    50  }
    51  
    52  type TypedData struct {
    53  	Types       Types            `json:"types"`
    54  	PrimaryType string           `json:"primaryType"`
    55  	Domain      TypedDataDomain  `json:"domain"`
    56  	Message     TypedDataMessage `json:"message"`
    57  }
    58  
    59  type Type struct {
    60  	Name string `json:"name"`
    61  	Type string `json:"type"`
    62  }
    63  
    64  func (t *Type) isArray() bool {
    65  	return strings.HasSuffix(t.Type, "[]")
    66  }
    67  
    68  // typeName returns the canonical name of the type. If the type is 'Person[]', then
    69  // this method returns 'Person'
    70  func (t *Type) typeName() string {
    71  	if strings.HasSuffix(t.Type, "[]") {
    72  		return strings.TrimSuffix(t.Type, "[]")
    73  	}
    74  	return t.Type
    75  }
    76  
    77  func (t *Type) isReferenceType() bool {
    78  	if t.Type == "" {
    79  		return false
    80  	}
    81  	// Reference types must have a leading uppercase character
    82  	firstLetter, _ := utf8.DecodeRuneInString(t.Type)
    83  	return unicode.IsUpper(firstLetter)
    84  }
    85  
    86  type Types map[string][]Type
    87  
    88  type TypePriority struct {
    89  	Type  string
    90  	Value uint
    91  }
    92  
    93  type TypedDataMessage = map[string]interface{}
    94  
    95  type TypedDataDomain struct {
    96  	Name              string                `json:"name"`
    97  	Version           string                `json:"version"`
    98  	ChainId           *math.HexOrDecimal256 `json:"chainId"`
    99  	VerifyingContract string                `json:"verifyingContract"`
   100  	Salt              string                `json:"salt"`
   101  }
   102  
   103  var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Z](\w*)(\[\])?$`)
   104  
   105  // SignTextWithValidator signs the given message which can be further recovered
   106  // with the given validator.
   107  // hash = keccak256("\x19\x00"${address}${data}).
   108  func SignTextValidator(validatorData ValidatorData) (signature hexutil.Bytes, message string) {
   109  	msg := fmt.Sprintf("\x19\x00%s%s", string(validatorData.Address.Bytes()), string(validatorData.Message))
   110  	return crypto.Keccak256([]byte(msg)), msg
   111  }
   112  
   113  // ComputeTypedDataHash computes keccak hash of typed data for signing.
   114  func ComputeTypedDataHash(typedData TypedData) ([]byte, error) {
   115  	domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map())
   116  	if err != nil {
   117  		err = errors.Wrap(err, "failed to pack and hash typedData EIP712Domain")
   118  		return nil, err
   119  	}
   120  
   121  	typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
   122  	if err != nil {
   123  		err = errors.Wrap(err, "failed to pack and hash typedData primary type")
   124  		return nil, err
   125  	}
   126  
   127  	rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash)))
   128  	return crypto.Keccak256(rawData), nil
   129  }
   130  
   131  // HashStruct generates a keccak256 hash of the encoding of the provided data
   132  func (typedData *TypedData) HashStruct(primaryType string, data TypedDataMessage) (hexutil.Bytes, error) {
   133  	encodedData, err := typedData.EncodeData(primaryType, data, 1)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	return crypto.Keccak256(encodedData), nil
   138  }
   139  
   140  // Dependencies returns an array of custom types ordered by their hierarchical reference tree
   141  func (typedData *TypedData) Dependencies(primaryType string, found []string) []string {
   142  	// BUGFIX (Geth): cut array suffixes so we can lookup the type
   143  	primaryType = strings.TrimSuffix(primaryType, "[]")
   144  
   145  	includes := func(arr []string, str string) bool {
   146  		for _, obj := range arr {
   147  			if obj == str {
   148  				return true
   149  			}
   150  		}
   151  		return false
   152  	}
   153  
   154  	if includes(found, primaryType) {
   155  		return found
   156  	}
   157  	if typedData.Types[primaryType] == nil {
   158  		return found
   159  	}
   160  	found = append(found, primaryType)
   161  	for _, field := range typedData.Types[primaryType] {
   162  		for _, dep := range typedData.Dependencies(field.Type, found) {
   163  			if !includes(found, dep) {
   164  				found = append(found, dep)
   165  			}
   166  		}
   167  	}
   168  	return found
   169  }
   170  
   171  // EncodeType generates the following encoding:
   172  // `name ‖ "(" ‖ member₁ ‖ "," ‖ member₂ ‖ "," ‖ … ‖ memberₙ ")"`
   173  //
   174  // each member is written as `type ‖ " " ‖ name` encodings cascade down and are sorted by name
   175  func (typedData *TypedData) EncodeType(primaryType string) hexutil.Bytes {
   176  	// Get dependencies primary first, then alphabetical
   177  	deps := typedData.Dependencies(primaryType, []string{})
   178  	if len(deps) > 0 {
   179  		slicedDeps := deps[1:]
   180  		sort.Strings(slicedDeps)
   181  		deps = append([]string{primaryType}, slicedDeps...)
   182  	}
   183  
   184  	// Format as a string with fields
   185  	var buffer bytes.Buffer
   186  	for _, dep := range deps {
   187  		buffer.WriteString(dep)
   188  		buffer.WriteString("(")
   189  		for _, obj := range typedData.Types[dep] {
   190  			buffer.WriteString(obj.Type)
   191  			buffer.WriteString(" ")
   192  			buffer.WriteString(obj.Name)
   193  			buffer.WriteString(",")
   194  		}
   195  		buffer.Truncate(buffer.Len() - 1)
   196  		buffer.WriteString(")")
   197  	}
   198  
   199  	return buffer.Bytes()
   200  }
   201  
   202  // TypeHash creates the keccak256 hash  of the data
   203  func (typedData *TypedData) TypeHash(primaryType string) hexutil.Bytes {
   204  	return crypto.Keccak256(typedData.EncodeType(primaryType))
   205  }
   206  
   207  // EncodeData generates the following encoding:
   208  // `enc(value₁) ‖ enc(value₂) ‖ … ‖ enc(valueₙ)`
   209  //
   210  // each encoded member is 32-byte long
   211  func (typedData *TypedData) EncodeData(primaryType string, data map[string]interface{}, depth int) (hexutil.Bytes, error) {
   212  	if err := typedData.validate(); err != nil {
   213  		return nil, err
   214  	}
   215  
   216  	buffer := bytes.Buffer{}
   217  
   218  	// Verify extra data
   219  	if exp, got := len(typedData.Types[primaryType]), len(data); exp < got {
   220  		return nil, fmt.Errorf("there is extra data provided in the message (%d < %d)", exp, got)
   221  	}
   222  
   223  	// Add typehash
   224  	buffer.Write(typedData.TypeHash(primaryType))
   225  
   226  	// Add field contents. Structs and arrays have special handlers.
   227  	for _, field := range typedData.Types[primaryType] {
   228  		encType := field.Type
   229  		encValue := data[field.Name]
   230  		switch {
   231  		case encType[len(encType)-1:] == "]":
   232  			arrayValue, ok := encValue.([]interface{})
   233  			if !ok {
   234  				return nil, dataMismatchError(encType, encValue)
   235  			}
   236  
   237  			arrayBuffer := bytes.Buffer{}
   238  			parsedType := strings.Split(encType, "[")[0]
   239  			for _, item := range arrayValue {
   240  				if typedData.Types[parsedType] != nil {
   241  					mapValue, ok := item.(map[string]interface{})
   242  					if !ok {
   243  						return nil, dataMismatchError(parsedType, item)
   244  					}
   245  					encodedData, err := typedData.EncodeData(parsedType, mapValue, depth+1)
   246  					if err != nil {
   247  						return nil, err
   248  					}
   249  
   250  					// THIS PART IS CHANGED FROM Geth's
   251  					//
   252  					// Metamask [signTypedData_v4]: The behavior instead was to encode array values as the keccak256 of the
   253  					// concatenated keccak256 of the values.
   254  					//
   255  					// See https://github.com/MetaMask/eth-sig-util/issues/106
   256  					// And https://github.com/MetaMask/eth-sig-util/pull/107/files
   257  					//
   258  					// N.B.: Can be reverted to original, once the fix is rolled for everyone
   259  					arrayBuffer.Write(crypto.Keccak256(encodedData))
   260  				} else {
   261  					bytesValue, err := typedData.EncodePrimitiveValue(parsedType, item, depth)
   262  					if err != nil {
   263  						return nil, err
   264  					}
   265  					arrayBuffer.Write(bytesValue)
   266  				}
   267  			}
   268  
   269  			buffer.Write(crypto.Keccak256(arrayBuffer.Bytes()))
   270  		case typedData.Types[field.Type] != nil:
   271  			mapValue, ok := encValue.(map[string]interface{})
   272  			if !ok {
   273  				return nil, dataMismatchError(encType, encValue)
   274  			}
   275  			encodedData, err := typedData.EncodeData(field.Type, mapValue, depth+1)
   276  			if err != nil {
   277  				return nil, err
   278  			}
   279  			buffer.Write(crypto.Keccak256(encodedData))
   280  		default:
   281  			byteValue, err := typedData.EncodePrimitiveValue(encType, encValue, depth)
   282  			if err != nil {
   283  				return nil, err
   284  			}
   285  			buffer.Write(byteValue)
   286  		}
   287  	}
   288  
   289  	return buffer.Bytes(), nil
   290  }
   291  
   292  // Attempt to parse bytes in different formats: byte array, hex string, hexutil.Bytes.
   293  func parseBytes(encType interface{}) ([]byte, bool) {
   294  	switch v := encType.(type) {
   295  	case []byte:
   296  		return v, true
   297  	case hexutil.Bytes:
   298  		return v, true
   299  	case string:
   300  		b, err := hexutil.Decode(v)
   301  		if err != nil {
   302  			return nil, false
   303  		}
   304  		return b, true
   305  	default:
   306  		return nil, false
   307  	}
   308  }
   309  
   310  func parseInteger(encType string, encValue interface{}) (*big.Int, error) {
   311  	var (
   312  		length int
   313  		signed = strings.HasPrefix(encType, "int")
   314  		b      *big.Int
   315  	)
   316  	if encType == "int" || encType == "uint" {
   317  		length = 256
   318  	} else {
   319  		lengthStr := ""
   320  		if strings.HasPrefix(encType, "uint") {
   321  			lengthStr = strings.TrimPrefix(encType, "uint")
   322  		} else {
   323  			lengthStr = strings.TrimPrefix(encType, "int")
   324  		}
   325  		atoiSize, err := strconv.Atoi(lengthStr)
   326  		if err != nil {
   327  			return nil, fmt.Errorf("invalid size on integer: %v", lengthStr)
   328  		}
   329  		length = atoiSize
   330  	}
   331  	switch v := encValue.(type) {
   332  	case *math.HexOrDecimal256:
   333  		b = (*big.Int)(v)
   334  	case string:
   335  		var hexIntValue math.HexOrDecimal256
   336  		if err := hexIntValue.UnmarshalText([]byte(v)); err != nil {
   337  			return nil, err
   338  		}
   339  		b = (*big.Int)(&hexIntValue)
   340  	case float64:
   341  		// JSON parses non-strings as float64. Fail if we cannot
   342  		// convert it losslessly
   343  		if float64(int64(v)) == v {
   344  			b = big.NewInt(int64(v))
   345  		} else {
   346  			return nil, fmt.Errorf("invalid float value %v for type %v", v, encType)
   347  		}
   348  	}
   349  	if b == nil {
   350  		return nil, fmt.Errorf("invalid integer value %v/%v for type %v", encValue, reflect.TypeOf(encValue), encType)
   351  	}
   352  	if b.BitLen() > length {
   353  		return nil, fmt.Errorf("integer larger than '%v'", encType)
   354  	}
   355  	if !signed && b.Sign() == -1 {
   356  		return nil, fmt.Errorf("invalid negative value for unsigned type %v", encType)
   357  	}
   358  	return b, nil
   359  }
   360  
   361  // EncodePrimitiveValue deals with the primitive values found
   362  // while searching through the typed data
   363  func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interface{}, depth int) ([]byte, error) {
   364  	switch encType {
   365  	case "address":
   366  		stringValue, ok := encValue.(string)
   367  		if !ok || !common.IsHexAddress(stringValue) {
   368  			return nil, dataMismatchError(encType, encValue)
   369  		}
   370  		retval := make([]byte, 32)
   371  		copy(retval[12:], common.HexToAddress(stringValue).Bytes())
   372  		return retval, nil
   373  	case "bool":
   374  		boolValue, ok := encValue.(bool)
   375  		if !ok {
   376  			return nil, dataMismatchError(encType, encValue)
   377  		}
   378  		if boolValue {
   379  			return math.PaddedBigBytes(common.Big1, 32), nil
   380  		}
   381  		return math.PaddedBigBytes(common.Big0, 32), nil
   382  	case "string":
   383  		strVal, ok := encValue.(string)
   384  		if !ok {
   385  			return nil, dataMismatchError(encType, encValue)
   386  		}
   387  		return crypto.Keccak256([]byte(strVal)), nil
   388  	case "bytes":
   389  		bytesValue, ok := parseBytes(encValue)
   390  		if !ok {
   391  			return nil, dataMismatchError(encType, encValue)
   392  		}
   393  		return crypto.Keccak256(bytesValue), nil
   394  	}
   395  	if strings.HasPrefix(encType, "bytes") {
   396  		lengthStr := strings.TrimPrefix(encType, "bytes")
   397  		length, err := strconv.Atoi(lengthStr)
   398  		if err != nil {
   399  			return nil, fmt.Errorf("invalid size on bytes: %v", lengthStr)
   400  		}
   401  		if length < 0 || length > 32 {
   402  			return nil, fmt.Errorf("invalid size on bytes: %d", length)
   403  		}
   404  		if byteValue, ok := parseBytes(encValue); !ok || len(byteValue) != length {
   405  			return nil, dataMismatchError(encType, encValue)
   406  		} else {
   407  			// Right-pad the bits
   408  			dst := make([]byte, 32)
   409  			copy(dst, byteValue)
   410  			return dst, nil
   411  		}
   412  	}
   413  	if strings.HasPrefix(encType, "int") || strings.HasPrefix(encType, "uint") {
   414  		b, err := parseInteger(encType, encValue)
   415  		if err != nil {
   416  			return nil, err
   417  		}
   418  		return math.U256Bytes(b), nil
   419  	}
   420  	return nil, fmt.Errorf("unrecognized type '%s'", encType)
   421  
   422  }
   423  
   424  // dataMismatchError generates an error for a mismatch between
   425  // the provided type and data
   426  func dataMismatchError(encType string, encValue interface{}) error {
   427  	return fmt.Errorf("provided data '%v' doesn't match type '%s'", encValue, encType)
   428  }
   429  
   430  // UnmarshalValidatorData converts the bytes input to typed data
   431  func UnmarshalValidatorData(data interface{}) (ValidatorData, error) {
   432  	raw, ok := data.(map[string]interface{})
   433  	if !ok {
   434  		return ValidatorData{}, errors.New("validator input is not a map[string]interface{}")
   435  	}
   436  	addr, ok := raw["address"].(string)
   437  	if !ok {
   438  		return ValidatorData{}, errors.New("validator address is not sent as a string")
   439  	}
   440  	addrBytes, err := hexutil.Decode(addr)
   441  	if err != nil {
   442  		return ValidatorData{}, err
   443  	}
   444  	if !ok || len(addrBytes) == 0 {
   445  		return ValidatorData{}, errors.New("validator address is undefined")
   446  	}
   447  
   448  	message, ok := raw["message"].(string)
   449  	if !ok {
   450  		return ValidatorData{}, errors.New("message is not sent as a string")
   451  	}
   452  	messageBytes, err := hexutil.Decode(message)
   453  	if err != nil {
   454  		return ValidatorData{}, err
   455  	}
   456  	if !ok || len(messageBytes) == 0 {
   457  		return ValidatorData{}, errors.New("message is undefined")
   458  	}
   459  
   460  	return ValidatorData{
   461  		Address: common.BytesToAddress(addrBytes),
   462  		Message: messageBytes,
   463  	}, nil
   464  }
   465  
   466  // validate makes sure the types are sound
   467  func (typedData *TypedData) validate() error {
   468  	if err := typedData.Types.validate(); err != nil {
   469  		return err
   470  	}
   471  	if err := typedData.Domain.validate(); err != nil {
   472  		return err
   473  	}
   474  	return nil
   475  }
   476  
   477  // Map generates a map version of the typed data
   478  func (typedData *TypedData) Map() map[string]interface{} {
   479  	dataMap := map[string]interface{}{
   480  		"types":       typedData.Types,
   481  		"domain":      typedData.Domain.Map(),
   482  		"primaryType": typedData.PrimaryType,
   483  		"message":     typedData.Message,
   484  	}
   485  	return dataMap
   486  }
   487  
   488  // Format returns a representation of typedData, which can be easily displayed by a user-interface
   489  // without in-depth knowledge about 712 rules
   490  func (typedData *TypedData) Format() ([]*NameValueType, error) {
   491  	domain, err := typedData.formatData("EIP712Domain", typedData.Domain.Map())
   492  	if err != nil {
   493  		return nil, err
   494  	}
   495  	ptype, err := typedData.formatData(typedData.PrimaryType, typedData.Message)
   496  	if err != nil {
   497  		return nil, err
   498  	}
   499  	var nvts []*NameValueType
   500  	nvts = append(nvts, &NameValueType{
   501  		Name:  "EIP712Domain",
   502  		Value: domain,
   503  		Typ:   "domain",
   504  	}, &NameValueType{
   505  		Name:  typedData.PrimaryType,
   506  		Value: ptype,
   507  		Typ:   "primary type",
   508  	})
   509  	return nvts, nil
   510  }
   511  
   512  func (typedData *TypedData) formatData(primaryType string, data map[string]interface{}) ([]*NameValueType, error) {
   513  	output := []*NameValueType{}
   514  
   515  	// Add field contents. Structs and arrays have special handlers.
   516  	for _, field := range typedData.Types[primaryType] {
   517  		encName := field.Name
   518  		encValue := data[encName]
   519  		item := &NameValueType{
   520  			Name: encName,
   521  			Typ:  field.Type,
   522  		}
   523  		switch {
   524  		case field.isArray():
   525  			arrayValue, _ := encValue.([]interface{})
   526  			parsedType := field.typeName()
   527  			for _, v := range arrayValue {
   528  				if typedData.Types[parsedType] != nil {
   529  					mapValue, _ := v.(map[string]interface{})
   530  					mapOutput, err := typedData.formatData(parsedType, mapValue)
   531  					if err != nil {
   532  						return nil, err
   533  					}
   534  					item.Value = mapOutput
   535  				} else {
   536  					primitiveOutput, err := formatPrimitiveValue(field.Type, encValue)
   537  					if err != nil {
   538  						return nil, err
   539  					}
   540  					item.Value = primitiveOutput
   541  				}
   542  			}
   543  		case typedData.Types[field.Type] != nil:
   544  			if mapValue, ok := encValue.(map[string]interface{}); ok {
   545  				mapOutput, err := typedData.formatData(field.Type, mapValue)
   546  				if err != nil {
   547  					return nil, err
   548  				}
   549  				item.Value = mapOutput
   550  			} else {
   551  				item.Value = "<nil>"
   552  			}
   553  		default:
   554  			primitiveOutput, err := formatPrimitiveValue(field.Type, encValue)
   555  			if err != nil {
   556  				return nil, err
   557  			}
   558  			item.Value = primitiveOutput
   559  		}
   560  		output = append(output, item)
   561  	}
   562  	return output, nil
   563  }
   564  
   565  func formatPrimitiveValue(encType string, encValue interface{}) (string, error) {
   566  	switch encType {
   567  	case "address":
   568  		if stringValue, ok := encValue.(string); !ok {
   569  			return "", fmt.Errorf("could not format value %v as address", encValue)
   570  		} else {
   571  			return common.HexToAddress(stringValue).String(), nil
   572  		}
   573  	case "bool":
   574  		if boolValue, ok := encValue.(bool); !ok {
   575  			return "", fmt.Errorf("could not format value %v as bool", encValue)
   576  		} else {
   577  			return fmt.Sprintf("%t", boolValue), nil
   578  		}
   579  	case "bytes", "string":
   580  		return fmt.Sprintf("%s", encValue), nil
   581  	}
   582  	if strings.HasPrefix(encType, "bytes") {
   583  		return fmt.Sprintf("%s", encValue), nil
   584  
   585  	}
   586  	if strings.HasPrefix(encType, "uint") || strings.HasPrefix(encType, "int") {
   587  		if b, err := parseInteger(encType, encValue); err != nil {
   588  			return "", err
   589  		} else {
   590  			return fmt.Sprintf("%d (0x%x)", b, b), nil
   591  		}
   592  	}
   593  	return "", fmt.Errorf("unhandled type %v", encType)
   594  }
   595  
   596  // NameValueType is a very simple struct with Name, Value and Type. It's meant for simple
   597  // json structures used to communicate signing-info about typed data with the UI
   598  type NameValueType struct {
   599  	Name  string      `json:"name"`
   600  	Value interface{} `json:"value"`
   601  	Typ   string      `json:"type"`
   602  }
   603  
   604  // Pprint returns a pretty-printed version of nvt
   605  func (nvt *NameValueType) Pprint(depth int) string {
   606  	output := bytes.Buffer{}
   607  	output.WriteString(strings.Repeat("\u00a0", depth*2))
   608  	output.WriteString(fmt.Sprintf("%s [%s]: ", nvt.Name, nvt.Typ))
   609  	if nvts, ok := nvt.Value.([]*NameValueType); ok {
   610  		output.WriteString("\n")
   611  		for _, next := range nvts {
   612  			sublevel := next.Pprint(depth + 1)
   613  			output.WriteString(sublevel)
   614  		}
   615  	} else {
   616  		if nvt.Value != nil {
   617  			output.WriteString(fmt.Sprintf("%q\n", nvt.Value))
   618  		} else {
   619  			output.WriteString("\n")
   620  		}
   621  	}
   622  	return output.String()
   623  }
   624  
   625  // Validate checks if the types object is conformant to the specs
   626  func (t Types) validate() error {
   627  	for typeKey, typeArr := range t {
   628  		if typeKey == "" {
   629  			return fmt.Errorf("empty type key")
   630  		}
   631  		for i, typeObj := range typeArr {
   632  			if typeObj.Type == "" {
   633  				return fmt.Errorf("type %q:%d: empty Type", typeKey, i)
   634  			}
   635  			if typeObj.Name == "" {
   636  				return fmt.Errorf("type %q:%d: empty Name", typeKey, i)
   637  			}
   638  			if typeKey == typeObj.Type {
   639  				return fmt.Errorf("type %q cannot reference itself", typeObj.Type)
   640  			}
   641  			if typeObj.isReferenceType() {
   642  				if _, exist := t[typeObj.typeName()]; !exist {
   643  					return fmt.Errorf("reference type %q is undefined", typeObj.Type)
   644  				}
   645  				if !typedDataReferenceTypeRegexp.MatchString(typeObj.Type) {
   646  					return fmt.Errorf("unknown reference type %q", typeObj.Type)
   647  				}
   648  			} else if !isPrimitiveTypeValid(typeObj.Type) {
   649  				return fmt.Errorf("unknown type %q", typeObj.Type)
   650  			}
   651  		}
   652  	}
   653  	return nil
   654  }
   655  
   656  // Checks if the primitive value is valid
   657  func isPrimitiveTypeValid(primitiveType string) bool {
   658  	if primitiveType == "address" ||
   659  		primitiveType == "address[]" ||
   660  		primitiveType == "bool" ||
   661  		primitiveType == "bool[]" ||
   662  		primitiveType == "string" ||
   663  		primitiveType == "string[]" {
   664  		return true
   665  	}
   666  	if primitiveType == "bytes" ||
   667  		primitiveType == "bytes[]" ||
   668  		primitiveType == "bytes1" ||
   669  		primitiveType == "bytes1[]" ||
   670  		primitiveType == "bytes2" ||
   671  		primitiveType == "bytes2[]" ||
   672  		primitiveType == "bytes3" ||
   673  		primitiveType == "bytes3[]" ||
   674  		primitiveType == "bytes4" ||
   675  		primitiveType == "bytes4[]" ||
   676  		primitiveType == "bytes5" ||
   677  		primitiveType == "bytes5[]" ||
   678  		primitiveType == "bytes6" ||
   679  		primitiveType == "bytes6[]" ||
   680  		primitiveType == "bytes7" ||
   681  		primitiveType == "bytes7[]" ||
   682  		primitiveType == "bytes8" ||
   683  		primitiveType == "bytes8[]" ||
   684  		primitiveType == "bytes9" ||
   685  		primitiveType == "bytes9[]" ||
   686  		primitiveType == "bytes10" ||
   687  		primitiveType == "bytes10[]" ||
   688  		primitiveType == "bytes11" ||
   689  		primitiveType == "bytes11[]" ||
   690  		primitiveType == "bytes12" ||
   691  		primitiveType == "bytes12[]" ||
   692  		primitiveType == "bytes13" ||
   693  		primitiveType == "bytes13[]" ||
   694  		primitiveType == "bytes14" ||
   695  		primitiveType == "bytes14[]" ||
   696  		primitiveType == "bytes15" ||
   697  		primitiveType == "bytes15[]" ||
   698  		primitiveType == "bytes16" ||
   699  		primitiveType == "bytes16[]" ||
   700  		primitiveType == "bytes17" ||
   701  		primitiveType == "bytes17[]" ||
   702  		primitiveType == "bytes18" ||
   703  		primitiveType == "bytes18[]" ||
   704  		primitiveType == "bytes19" ||
   705  		primitiveType == "bytes19[]" ||
   706  		primitiveType == "bytes20" ||
   707  		primitiveType == "bytes20[]" ||
   708  		primitiveType == "bytes21" ||
   709  		primitiveType == "bytes21[]" ||
   710  		primitiveType == "bytes22" ||
   711  		primitiveType == "bytes22[]" ||
   712  		primitiveType == "bytes23" ||
   713  		primitiveType == "bytes23[]" ||
   714  		primitiveType == "bytes24" ||
   715  		primitiveType == "bytes24[]" ||
   716  		primitiveType == "bytes25" ||
   717  		primitiveType == "bytes25[]" ||
   718  		primitiveType == "bytes26" ||
   719  		primitiveType == "bytes26[]" ||
   720  		primitiveType == "bytes27" ||
   721  		primitiveType == "bytes27[]" ||
   722  		primitiveType == "bytes28" ||
   723  		primitiveType == "bytes28[]" ||
   724  		primitiveType == "bytes29" ||
   725  		primitiveType == "bytes29[]" ||
   726  		primitiveType == "bytes30" ||
   727  		primitiveType == "bytes30[]" ||
   728  		primitiveType == "bytes31" ||
   729  		primitiveType == "bytes31[]" ||
   730  		primitiveType == "bytes32" ||
   731  		primitiveType == "bytes32[]" {
   732  		return true
   733  	}
   734  	if primitiveType == "int" ||
   735  		primitiveType == "int[]" ||
   736  		primitiveType == "int8" ||
   737  		primitiveType == "int8[]" ||
   738  		primitiveType == "int16" ||
   739  		primitiveType == "int16[]" ||
   740  		primitiveType == "int32" ||
   741  		primitiveType == "int32[]" ||
   742  		primitiveType == "int64" ||
   743  		primitiveType == "int64[]" ||
   744  		primitiveType == "int128" ||
   745  		primitiveType == "int128[]" ||
   746  		primitiveType == "int256" ||
   747  		primitiveType == "int256[]" {
   748  		return true
   749  	}
   750  	if primitiveType == "uint" ||
   751  		primitiveType == "uint[]" ||
   752  		primitiveType == "uint8" ||
   753  		primitiveType == "uint8[]" ||
   754  		primitiveType == "uint16" ||
   755  		primitiveType == "uint16[]" ||
   756  		primitiveType == "uint32" ||
   757  		primitiveType == "uint32[]" ||
   758  		primitiveType == "uint64" ||
   759  		primitiveType == "uint64[]" ||
   760  		primitiveType == "uint128" ||
   761  		primitiveType == "uint128[]" ||
   762  		primitiveType == "uint256" ||
   763  		primitiveType == "uint256[]" {
   764  		return true
   765  	}
   766  	return false
   767  }
   768  
   769  // validate checks if the given domain is valid, i.e. contains at least
   770  // the minimum viable keys and values
   771  func (domain *TypedDataDomain) validate() error {
   772  	if domain.ChainId == nil && domain.Name == "" && domain.Version == "" && domain.VerifyingContract == "" && domain.Salt == "" {
   773  		return errors.New("domain is undefined")
   774  	}
   775  
   776  	return nil
   777  }
   778  
   779  // Map is a helper function to generate a map version of the domain
   780  func (domain *TypedDataDomain) Map() map[string]interface{} {
   781  	dataMap := map[string]interface{}{}
   782  
   783  	if domain.ChainId != nil {
   784  		dataMap["chainId"] = domain.ChainId
   785  	}
   786  
   787  	if domain.Name != "" {
   788  		dataMap["name"] = domain.Name
   789  	}
   790  
   791  	if domain.Version != "" {
   792  		dataMap["version"] = domain.Version
   793  	}
   794  
   795  	if domain.VerifyingContract != "" {
   796  		dataMap["verifyingContract"] = domain.VerifyingContract
   797  	}
   798  
   799  	if domain.Salt != "" {
   800  		dataMap["salt"] = domain.Salt
   801  	}
   802  	return dataMap
   803  }