@@ -2,10 +2,8 @@ package ethcoder
22
33import (
44 "bytes"
5- "encoding/json"
65 "fmt"
76 "math/big"
8- "slices"
97 "sort"
108 "strings"
119
@@ -269,234 +267,3 @@ func (t *TypedData) EncodeDigest() ([]byte, error) {
269267 }
270268 return digest , nil
271269}
272-
273- func TypedDataFromJSON (typedDataJSON string ) (* TypedData , error ) {
274- var typedData TypedData
275- err := json .Unmarshal ([]byte (typedDataJSON ), & typedData )
276- if err != nil {
277- return nil , err
278- }
279- return & typedData , nil
280- }
281-
282- func (t * TypedData ) UnmarshalJSON (data []byte ) error {
283- // Intermediary structure to decode message field
284- type TypedDataRaw struct {
285- Types TypedDataTypes `json:"types"`
286- PrimaryType string `json:"primaryType"`
287- Domain struct {
288- Name string `json:"name,omitempty"`
289- Version string `json:"version,omitempty"`
290- ChainID interface {} `json:"chainId,omitempty"`
291- VerifyingContract * common.Address `json:"verifyingContract,omitempty"`
292- Salt * common.Hash `json:"salt,omitempty"`
293- } `json:"domain"`
294- Message map [string ]interface {} `json:"message"`
295- }
296-
297- // Json decoder with json.Number support, so that we can decode big.Int values
298- dec := json .NewDecoder (bytes .NewReader (data ))
299- dec .UseNumber ()
300-
301- var raw TypedDataRaw
302- if err := dec .Decode (& raw ); err != nil {
303- return err
304- }
305-
306- // Ensure the "EIP712Domain" type is defined. In case its not defined
307- // we will add it to the types map
308- _ , ok := raw .Types ["EIP712Domain" ]
309- if ! ok {
310- raw .Types ["EIP712Domain" ] = []TypedDataArgument {}
311- if raw .Domain .Name != "" {
312- raw .Types ["EIP712Domain" ] = append (raw .Types ["EIP712Domain" ], TypedDataArgument {Name : "name" , Type : "string" })
313- }
314- if raw .Domain .Version != "" {
315- raw .Types ["EIP712Domain" ] = append (raw .Types ["EIP712Domain" ], TypedDataArgument {Name : "version" , Type : "string" })
316- }
317- if raw .Domain .ChainID != nil {
318- raw .Types ["EIP712Domain" ] = append (raw .Types ["EIP712Domain" ], TypedDataArgument {Name : "chainId" , Type : "uint256" })
319- }
320- if raw .Domain .VerifyingContract != nil {
321- raw .Types ["EIP712Domain" ] = append (raw .Types ["EIP712Domain" ], TypedDataArgument {Name : "verifyingContract" , Type : "address" })
322- }
323- if raw .Domain .Salt != nil {
324- raw .Types ["EIP712Domain" ] = append (raw .Types ["EIP712Domain" ], TypedDataArgument {Name : "salt" , Type : "bytes32" })
325- }
326- }
327-
328- // Ensure primary type is defined
329- if raw .PrimaryType == "" {
330- // detect primary type if its unspecified
331- primaryType , err := typedDataDetectPrimaryType (raw .Types .Map (), raw .Message )
332- if err != nil {
333- return err
334- }
335- raw .PrimaryType = primaryType
336- }
337- _ , ok = raw .Types [raw .PrimaryType ]
338- if ! ok {
339- return fmt .Errorf ("primary type '%s' is not defined" , raw .PrimaryType )
340- }
341-
342- // Decode the domain, which is mostly decooded except the chainId is an interface{} type
343- // because the value may be a number of a hex encoded number. We want it in a big.Int.
344- domain := TypedDataDomain {
345- Name : raw .Domain .Name ,
346- Version : raw .Domain .Version ,
347- ChainID : nil ,
348- VerifyingContract : raw .Domain .VerifyingContract ,
349- Salt : raw .Domain .Salt ,
350- }
351- if raw .Domain .ChainID != nil {
352- chainID := big .NewInt (0 )
353- if val , ok := raw .Domain .ChainID .(float64 ); ok {
354- chainID .SetInt64 (int64 (val ))
355- } else if val , ok := raw .Domain .ChainID .(json.Number ); ok {
356- chainID .SetString (val .String (), 10 )
357- } else if val , ok := raw .Domain .ChainID .(string ); ok {
358- if strings .HasPrefix (val , "0x" ) {
359- chainID .SetString (val [2 :], 16 )
360- } else {
361- chainID .SetString (val , 10 )
362- }
363- }
364- domain .ChainID = chainID
365- }
366-
367- // Decode the raw message into Go runtime types
368- message , err := typedDataDecodeRawMessageMap (raw .Types .Map (), raw .PrimaryType , raw .Message )
369- if err != nil {
370- return err
371- }
372-
373- t .Types = raw .Types
374- t .PrimaryType = raw .PrimaryType
375- t .Domain = domain
376-
377- m , ok := message .(map [string ]interface {})
378- if ! ok {
379- return fmt .Errorf ("resulting message is not a map" )
380- }
381- t .Message = m
382-
383- return nil
384- }
385-
386- func typedDataDetectPrimaryType (typesMap map [string ]map [string ]string , message map [string ]interface {}) (string , error ) {
387- // If there are only two types, and one is the EIP712Domain, then the other is the primary type
388- if len (typesMap ) == 2 {
389- _ , ok := typesMap ["EIP712Domain" ]
390- if ok {
391- for typ := range typesMap {
392- if typ == "EIP712Domain" {
393- continue
394- }
395- return typ , nil
396- }
397- }
398- }
399-
400- // Otherwise search for the primary type by looking for the first type that has a message field keys
401- messageKeys := []string {}
402- for k := range message {
403- messageKeys = append (messageKeys , k )
404- }
405- sort .Strings (messageKeys )
406-
407- for typ := range typesMap {
408- if typ == "EIP712Domain" {
409- continue
410- }
411- if len (typesMap [typ ]) != len (messageKeys ) {
412- continue
413- }
414-
415- typKeys := []string {}
416- for k := range typesMap [typ ] {
417- typKeys = append (typKeys , k )
418- }
419- sort .Strings (typKeys )
420-
421- if ! slices .Equal (messageKeys , typKeys ) {
422- continue
423- }
424- return typ , nil
425- }
426-
427- return "" , fmt .Errorf ("no primary type found" )
428- }
429-
430- func typedDataDecodeRawMessageMap (typesMap map [string ]map [string ]string , primaryType string , data interface {}) (interface {}, error ) {
431- // Handle array types
432- if arr , ok := data .([]interface {}); ok {
433- results := make ([]interface {}, len (arr ))
434- for i , item := range arr {
435- decoded , err := typedDataDecodeRawMessageMap (typesMap , primaryType , item )
436- if err != nil {
437- return nil , err
438- }
439- results [i ] = decoded
440- }
441- return results , nil
442- }
443-
444- // Handle primitive directly
445- message , ok := data .(map [string ]interface {})
446- if ! ok {
447- return typedDataDecodePrimitiveValue (primaryType , data )
448- }
449-
450- currentType , ok := typesMap [primaryType ]
451- if ! ok {
452- return nil , fmt .Errorf ("type %s is not defined" , primaryType )
453- }
454-
455- processedMessage := make (map [string ]interface {})
456- for k , v := range message {
457- typ , ok := currentType [k ]
458- if ! ok {
459- return nil , fmt .Errorf ("message field '%s' is missing type definition on '%s'" , k , primaryType )
460- }
461-
462- // Extract base type and check if it's an array
463- baseType := typ
464- isArray := false
465- if idx := strings .Index (typ , "[" ); idx != - 1 {
466- baseType = typ [:idx ]
467- isArray = true
468- }
469-
470- // Process value based on whether it's a custom or primitive type
471- if _ , isCustomType := typesMap [baseType ]; isCustomType {
472- decoded , err := typedDataDecodeRawMessageMap (typesMap , baseType , v )
473- if err != nil {
474- return nil , err
475- }
476- processedMessage [k ] = decoded
477- } else {
478- var decoded interface {}
479- var err error
480- if isArray {
481- decoded , err = typedDataDecodeRawMessageMap (typesMap , baseType , v )
482- } else {
483- decoded , err = typedDataDecodePrimitiveValue (baseType , v )
484- }
485- if err != nil {
486- return nil , fmt .Errorf ("failed to decode field '%s': %w" , k , err )
487- }
488- processedMessage [k ] = decoded
489- }
490- }
491-
492- return processedMessage , nil
493- }
494-
495- func typedDataDecodePrimitiveValue (typ string , value interface {}) (interface {}, error ) {
496- val := fmt .Sprintf ("%v" , value )
497- out , err := ABIUnmarshalStringValuesAny ([]string {typ }, []any {val })
498- if err != nil {
499- return nil , fmt .Errorf ("typedDataDecodePrimitiveValue: %w" , err )
500- }
501- return out [0 ], nil
502- }
0 commit comments