diff --git a/cmd/clef/README.md b/cmd/clef/README.md index 98e85d5a11..2e1dac2998 100644 --- a/cmd/clef/README.md +++ b/cmd/clef/README.md @@ -383,8 +383,8 @@ Response ```json { - "jsonrpc": "2.0", "id": 3, + "jsonrpc": "2.0", "result": "0x5b6693f153b48ec1c706ba4169960386dbaa6903e249cc79a8e6ddc434451d417e1e57327872c7f538beeb323c300afa9999a3d4a5de6caf3be0d5ef832b67ef1c" } ``` @@ -480,8 +480,8 @@ Response ```json { - "jsonrpc": "2.0", "id": 1, + "jsonrpc": "2.0", "result": "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c" } ``` diff --git a/signer/core/api.go b/signer/core/api.go index 33ec28bb8a..cfa09fb4c6 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -176,9 +176,9 @@ type ( ContentType string `json:"content_type"` Address common.MixedcaseAddress `json:"address"` Rawdata interface{} `json:"raw_data"` - Message []*NameValueType `json:"message"` - Hash hexutil.Bytes `json:"hash"` - Meta Metadata `json:"meta"` + Message []*NameValueType `json:"message"` + Hash hexutil.Bytes `json:"hash"` + Meta Metadata `json:"meta"` } SignDataResponse struct { Approved bool `json:"approved"` diff --git a/signer/core/signed_data.go b/signer/core/signed_data.go index bddb2b1001..710d0aa63e 100644 --- a/signer/core/signed_data.go +++ b/signer/core/signed_data.go @@ -116,8 +116,8 @@ type TypedDataDomain struct { Salt string `json:"salt"` } -var typedDataRegexp = regexp.MustCompile(`^((address|bool|bytes|string)|((bytes)([1-9]|[1-2][0-9]|3[0-2]))|((int|uint)(8|16|32|64|128|256)))(\[\])?$`) -var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Z](\w*)(\[])?$`) +// var typedDataRegexp = regexp.MustCompile(`^((address|bool|bytes|int|uint|string)|((bytes)([1-9]|[1-2][0-9]|3[0-2]))|((int|uint)(8|16|32|64|128|256)))(\[\])?$`) +var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Z](\w*)(\[\])?$`) // Sign receives a request and produces a signature @@ -299,9 +299,6 @@ func SignTextPlain(data hexutil.Bytes) (hexutil.Bytes, string) { // SignTypedData signs EIP-712 conformant typed data // hash = keccak256("\x19${byteVersion}${domainSeparator}${hashStruct(message)}") func (api *SignerAPI) SignTypedData(ctx context.Context, addr common.MixedcaseAddress, typedData TypedData) (hexutil.Bytes, error) { - if err := typedData.Validate(); err != nil { - return nil, err - } domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) if err != nil { return nil, err @@ -396,6 +393,10 @@ func (typedData *TypedData) TypeHash(primaryType string) hexutil.Bytes { // // each encoded member is 32-byte long func (typedData *TypedData) EncodeData(primaryType string, data map[string]interface{}, depth int) (hexutil.Bytes, error) { + if err := typedData.validate(); err != nil { + return nil, err + } + buffer := bytes.Buffer{} // Verify extra data @@ -430,7 +431,7 @@ func (typedData *TypedData) EncodeData(primaryType string, data map[string]inter } arrayBuffer.Write(encodedData) } else { - bytesValue, err := typedData.EncodePrimitiveValue(encType, encValue, depth) + bytesValue, err := typedData.EncodePrimitiveValue(parsedType, item, depth) if err != nil { return nil, err } @@ -495,15 +496,14 @@ func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interf } return crypto.Keccak256(bytesValue), nil } - // bytes32 etc if strings.HasPrefix(encType, "bytes") { - sizeStr := strings.TrimPrefix(encType, "bytes") - size, err := strconv.Atoi(sizeStr) + lengthStr := strings.TrimPrefix(encType, "bytes") + length, err := strconv.Atoi(lengthStr) if err != nil { - return nil, fmt.Errorf("invalid size on bytes: %v", sizeStr) + return nil, fmt.Errorf("invalid size on bytes: %v", lengthStr) } - if size < 0 || size > 32 { - return nil, fmt.Errorf("invalid size on bytes: %d", size) + if length < 0 || length > 32 { + return nil, fmt.Errorf("invalid size on bytes: %d", length) } if byteValue, ok := encValue.(hexutil.Bytes); !ok { return nil, dataMismatchError(encType, encValue) @@ -511,8 +511,22 @@ func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interf return math.PaddedBigBytes(new(big.Int).SetBytes(byteValue), 32), nil } } - if strings.HasPrefix(encType, "uint") || strings.HasPrefix(encType, "int") { + if strings.HasPrefix(encType, "int") || strings.HasPrefix(encType, "uint") { + length := 0 + if encType == "int" || encType == "uint" { + length = 256 + } else { + lengthStr := strings.TrimPrefix(strings.TrimPrefix(encType, "uint"), "int") + atoiSize, err := strconv.Atoi(lengthStr) + if err != nil { + return nil, fmt.Errorf("invalid size on integer: %v", lengthStr) + } + length = atoiSize + } bigIntValue, ok := encValue.(*big.Int) + if bigIntValue.BitLen() > length { + return nil, fmt.Errorf("integer larger than '%v'", encType) + } if !ok { return nil, dataMismatchError(encType, encValue) } @@ -591,12 +605,12 @@ func UnmarshalValidatorData(data interface{}) (ValidatorData, error) { }, nil } -// Validate make sure the types are sound -func (typedData *TypedData) Validate() error { - if err := typedData.Types.Validate(); err != nil { +// Validate makes sure the types are sound +func (typedData *TypedData) validate() error { + if err := typedData.Types.validate(); err != nil { return err } - if err := typedData.Domain.Validate(); err != nil { + if err := typedData.Domain.validate(); err != nil { return err } return nil @@ -724,7 +738,7 @@ func (nvt *NameValueType) Pprint(depth int) string { } // Validate checks if the types object is conformant to the specs -func (t Types) Validate() error { +func (t Types) validate() error { for typeKey, typeArr := range t { for _, typeObj := range typeArr { if typeKey == typeObj.Type { @@ -737,8 +751,7 @@ func (t Types) Validate() error { if !typedDataReferenceTypeRegexp.MatchString(typeObj.Type) { return fmt.Errorf("unknown reference type '%s", typeObj.Type) } - - } else if !typedDataRegexp.MatchString(typeObj.Type) { + } else if !isPrimitiveTypeValid(typeObj.Type) { return fmt.Errorf("unknown type '%s'", typeObj.Type) } } @@ -746,9 +759,120 @@ func (t Types) Validate() error { return nil } +// Checks if the primitive value is valid +func isPrimitiveTypeValid(primitiveType string) bool { + if primitiveType == "address" || + primitiveType == "address[]" || + primitiveType == "bool" || + primitiveType == "bool[]" || + primitiveType == "string" || + primitiveType == "string[]" { + return true + } + if primitiveType == "bytes" || + primitiveType == "bytes[]" || + primitiveType == "bytes1" || + primitiveType == "bytes1[]" || + primitiveType == "bytes2" || + primitiveType == "bytes2[]" || + primitiveType == "bytes3" || + primitiveType == "bytes3[]" || + primitiveType == "bytes4" || + primitiveType == "bytes4[]" || + primitiveType == "bytes5" || + primitiveType == "bytes5[]" || + primitiveType == "bytes6" || + primitiveType == "bytes6[]" || + primitiveType == "bytes7" || + primitiveType == "bytes7[]" || + primitiveType == "bytes8" || + primitiveType == "bytes8[]" || + primitiveType == "bytes9" || + primitiveType == "bytes9[]" || + primitiveType == "bytes10" || + primitiveType == "bytes10[]" || + primitiveType == "bytes11" || + primitiveType == "bytes11[]" || + primitiveType == "bytes12" || + primitiveType == "bytes12[]" || + primitiveType == "bytes13" || + primitiveType == "bytes13[]" || + primitiveType == "bytes14" || + primitiveType == "bytes14[]" || + primitiveType == "bytes15" || + primitiveType == "bytes15[]" || + primitiveType == "bytes16" || + primitiveType == "bytes16[]" || + primitiveType == "bytes17" || + primitiveType == "bytes17[]" || + primitiveType == "bytes18" || + primitiveType == "bytes18[]" || + primitiveType == "bytes19" || + primitiveType == "bytes19[]" || + primitiveType == "bytes20" || + primitiveType == "bytes20[]" || + primitiveType == "bytes21" || + primitiveType == "bytes21[]" || + primitiveType == "bytes22" || + primitiveType == "bytes22[]" || + primitiveType == "bytes23" || + primitiveType == "bytes23[]" || + primitiveType == "bytes24" || + primitiveType == "bytes24[]" || + primitiveType == "bytes25" || + primitiveType == "bytes25[]" || + primitiveType == "bytes26" || + primitiveType == "bytes26[]" || + primitiveType == "bytes27" || + primitiveType == "bytes27[]" || + primitiveType == "bytes28" || + primitiveType == "bytes28[]" || + primitiveType == "bytes29" || + primitiveType == "bytes29[]" || + primitiveType == "bytes30" || + primitiveType == "bytes30[]" || + primitiveType == "bytes31" || + primitiveType == "bytes31[]" { + return true + } + if primitiveType == "int" || + primitiveType == "int[]" || + primitiveType == "int8" || + primitiveType == "int8[]" || + primitiveType == "int16" || + primitiveType == "int16[]" || + primitiveType == "int32" || + primitiveType == "int32[]" || + primitiveType == "int64" || + primitiveType == "int64[]" || + primitiveType == "int128" || + primitiveType == "int128[]" || + primitiveType == "int256" || + primitiveType == "int256[]" { + return true + } + if primitiveType == "uint" || + primitiveType == "uint[]" || + primitiveType == "uint8" || + primitiveType == "uint8[]" || + primitiveType == "uint16" || + primitiveType == "uint16[]" || + primitiveType == "uint32" || + primitiveType == "uint32[]" || + primitiveType == "uint64" || + primitiveType == "uint64[]" || + primitiveType == "uint128" || + primitiveType == "uint128[]" || + primitiveType == "uint256" || + primitiveType == "uint256[]" { + return true + } + return false +} + // Validate checks if the given domain is valid, i.e. contains at least // the minimum viable keys and values -func (domain *TypedDataDomain) Validate() error { +func (domain *TypedDataDomain) validate() error { if domain.ChainId == big.NewInt(0) { return errors.New("chainId must be specified according to EIP-155") } diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index 63fb0402d0..7d44bce2ce 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -193,7 +193,7 @@ func TestSignData(t *testing.T) { t.Errorf("Expected nil-data, got %x", signature) } if err != keystore.ErrDecrypt { - t.Errorf("Expected ErrLocked! %v", err) + t.Errorf("Expected ErrLocked! '%v'", err) } control <- "No way" signature, err = api.SignData(context.Background(), TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) @@ -201,7 +201,7 @@ func TestSignData(t *testing.T) { t.Errorf("Expected nil-data, got %x", signature) } if err != ErrRequestDenied { - t.Errorf("Expected ErrRequestDenied! %v", err) + t.Errorf("Expected ErrRequestDenied! '%v'", err) } // text/plain control <- "Y" @@ -283,7 +283,7 @@ func TestMalformedDomainkeys(t *testing.T) { // "chainId": 1, // "vxerifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" //} - var jsonTypedData = ` + jsonTypedData := ` { "types": { "EIP712Domain": [ @@ -348,20 +348,106 @@ func TestMalformedDomainkeys(t *testing.T) { "contents": "Hello, Bob!" } } +` + var malformedDomainTypedData TypedData + err := json.Unmarshal([]byte(jsonTypedData), &malformedDomainTypedData) + if err != nil { + t.Fatalf("unmarshalling failed '%v'", err) + } + _, err = malformedDomainTypedData.HashStruct("EIP712Domain", malformedDomainTypedData.Domain.Map()) + if err == nil || err.Error() != "provided data '' doesn't match type 'address'" { + t.Errorf("Expected `provided data '' doesn't match type 'address'`, got '%v'", err) + } +} +func TestMalformedTypesAndExtradata(t *testing.T) { + // Verifies several quirks + // 1. Using dynamic types and only validating the prefix: + //{ + // "name": "chainId", + // "type": "uint256 ... and now for something completely different" + //} + // 2. Extra data in message: + //{ + // "blahonga": "zonk bonk" + //} + jsonTypedData := ` + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256 ... and now for something completely different" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Person": [ + { + "name": "name", + "type": "string" + }, + { + "name": "wallet", + "type": "address" + } + ], + "Mail": [ + { + "name": "from", + "type": "Person" + }, + { + "name": "to", + "type": "Person" + }, + { + "name": "contents", + "type": "string" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + } ` var malformedTypedData TypedData err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData) if err != nil { - t.Fatalf("unmarshalling failed %v", err) + t.Fatalf("unmarshalling failed '%v'", err) } - err = malformedTypedData.Validate() - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - _, err = malformedTypedData.HashStruct("EIP712Domain", malformedTypedData.Domain.Map()) - if err == nil || err.Error() != "provided data '' doesn't match type 'address'" { - t.Errorf("Expected `provided data '' doesn't match type 'address'`, got %v", err) + + malformedTypedData.Types["EIP712Domain"][2].Type = "uint256" + malformedTypedData.Message["blahonga"] = "zonk bonk" + _, err = malformedTypedData.HashStruct(malformedTypedData.PrimaryType, malformedTypedData.Message) + if err == nil || err.Error() != "there is extra data provided in the message" { + t.Errorf("Expected `there is extra data provided in the message`, got '%v'", err) } } @@ -447,173 +533,146 @@ func TestTypeMismatch(t *testing.T) { } } ` - var malformedTypedData TypedData - err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData) + var mismatchTypedData TypedData + err := json.Unmarshal([]byte(jsonTypedData), &mismatchTypedData) if err != nil { - t.Fatalf("unmarshalling failed %v", err) + t.Fatalf("unmarshalling failed '%v'", err) } - err = malformedTypedData.Validate() - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - _, err = malformedTypedData.HashStruct(malformedTypedData.PrimaryType, malformedTypedData.Message) + _, err = mismatchTypedData.HashStruct(mismatchTypedData.PrimaryType, mismatchTypedData.Message) if err.Error() != "provided data 'Hello, Bob!' doesn't match type 'Person'" { - t.Errorf("Expected `provided data 'Hello, Bob!' doesn't match type 'Person'`, got %v", err) + t.Errorf("Expected `provided data 'Hello, Bob!' doesn't match type 'Person'`, got '%v'", err) } - malformedTypedData.Types["Mail"][2].Type = "Blahonga" - err = malformedTypedData.Validate() + mismatchTypedData.Types["Mail"][2].Type = "Blahonga" + _, err = mismatchTypedData.HashStruct(mismatchTypedData.PrimaryType, mismatchTypedData.Message) if err == nil || err.Error() != "reference type 'Blahonga' is undefined" { - t.Fatalf("Expected `reference type 'Blahonga' is undefined`, got %v", err) - } - _, err = malformedTypedData.HashStruct(malformedTypedData.PrimaryType, malformedTypedData.Message) - if err == nil || err.Error() != "unrecognized type 'Blahonga'" { - t.Errorf("Expected `unrecognized type 'Blahonga'`, got %v", err) + t.Fatalf("Expected `reference type 'Blahonga' is undefined`, got '%v'", err) } } -func TestMalformedTypesAndExtradata(t *testing.T) { - // Verifies several quirks - // 1. Using dynamic types and only validating the prefix: - //{ - // "name": "chainId", - // "type": "uint256 ... and now for something completely different" - //} - // 2. Extra data in message: - //{ - // "blahonga": "zonk bonk" - //} - jsonTypedData := ` - { - "types": { - "EIP712Domain": [ - { - "name": "name", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "chainId", - "type": "uint256 ... and now for something completely different" - }, - { - "name": "verifyingContract", - "type": "address" - } - ], - "Person": [ - { - "name": "name", - "type": "string" - }, - { - "name": "wallet", - "type": "address" - } - ], - "Mail": [ - { - "name": "from", - "type": "Person" - }, - { - "name": "to", - "type": "Person" - }, - { - "name": "contents", - "type": "string" - } - ] - }, - "primaryType": "Mail", - "domain": { - "name": "Ether Mail", - "version": "1", - "chainId": 1, - "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" - }, - "message": { - "from": { - "name": "Cow", - "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" - }, - "to": { - "name": "Bob", - "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" - }, - "contents": "Hello, Bob!" - } - } -` - var malformedTypedData TypedData - err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData) - if err != nil { - t.Fatalf("unmarshalling failed %v", err) - } - err = malformedTypedData.Validate() - if err == nil || err.Error() != "unknown type 'uint256 ... and now for something completely different'" { - t.Fatalf("Expected `unknown type 'uint256 ... and now for something completely different'`, got %v", err) - } - - malformedTypedData.Types["EIP712Domain"][2].Type = "uint256" - malformedTypedData.Message["blahonga"] = "zonk bonk" - _, err = malformedTypedData.HashStruct(malformedTypedData.PrimaryType, malformedTypedData.Message) - if err == nil || err.Error() != "there is extra data provided in the message" { - t.Errorf("Expected `there is extra data provided in the message`, got %v", err) - } -} - -func TestTypeMismatch(t *testing.T) { +func TestTypeOverflow(t *testing.T) { // Verifies data that doesn't fit into it: //{ // "test": 65536 <-- test defined as uint8 //} - var malformedTypedData TypedData - err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData) + var overflowTypedData TypedData + err := json.Unmarshal([]byte(jsonTypedData), &overflowTypedData) if err != nil { - t.Fatalf("unmarshalling failed %v", err) + t.Fatalf("unmarshalling failed '%v'", err) } // Set test to something outside uint8 - (malformedTypedData.Message["from"]).(map[string]interface{})["test"] = 65536 + (overflowTypedData.Message["from"]).(map[string]interface{})["test"] = big.NewInt(65536) - err = malformedTypedData.Validate() - if err != nil { - t.Fatalf("Expected no error, got %v", err) + _, err = overflowTypedData.HashStruct(overflowTypedData.PrimaryType, overflowTypedData.Message) + if err == nil || err.Error() != "integer larger than 'uint8'" { + t.Fatalf("Expected `integer larger than 'uint8'`, got '%v'", err) } - _, err = malformedTypedData.HashStruct(malformedTypedData.PrimaryType, malformedTypedData.Message) - if err == nil || err.Error() != "provided data '65536' doesn't match type 'uint8'" { - t.Fatalf("Expected `provided data '65536' doesn't match type 'uint8'`, got %v", err) - } + (overflowTypedData.Message["from"]).(map[string]interface{})["test"] = big.NewInt(3) + (overflowTypedData.Message["to"]).(map[string]interface{})["test"] = big.NewInt(4) - (malformedTypedData.Message["from"]).(map[string]interface{})["test"] = big.NewInt(3) - (malformedTypedData.Message["to"]).(map[string]interface{})["test"] = big.NewInt(4) - - _, err = malformedTypedData.HashStruct(malformedTypedData.PrimaryType, malformedTypedData.Message) + _, err = overflowTypedData.HashStruct(overflowTypedData.PrimaryType, overflowTypedData.Message) if err != nil { - t.Fatalf("Expected no err, got %v", err) + t.Fatalf("Expected no err, got '%v'", err) } } -func TestFormatter(t *testing.T) { +func TestArray(t *testing.T) { + // Makes sure that arrays work fine + //{ + // "type": "address[]" + //}, + //{ + // "type": "string[]" + //}, + //{ + // "type": "uint16[]", + //} - var d TypedData - err := json.Unmarshal([]byte(jsonTypedData), &d) + jsonTypedData := ` + { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Foo": [ + { + "name": "bar", + "type": "address[]" + } + ] + }, + "primaryType": "Foo", + "domain": { + "name": "Lorem", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "bar": [ + "0x0000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000003" + ] + } + } + ` + var arrayTypedData TypedData + err := json.Unmarshal([]byte(jsonTypedData), &arrayTypedData) if err != nil { - t.Fatalf("unmarshalling failed %v", err) + t.Fatalf("unmarshalling failed '%v'", err) } - formatted := d.Format() - for _, item := range formatted { - fmt.Printf("%v\n", item.Pprint(0)) + _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) + if err != nil { + t.Fatalf("Expected no err, got '%v'", err) } - j, _ := json.Marshal(formatted) - fmt.Printf("%v\n", string(j)) + // Change array to string + arrayTypedData.Types["Foo"][0].Type = "string[]" + arrayTypedData.Message["bar"] = []interface{}{ + "lorem", + "ipsum", + "dolores", + } + _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) + if err != nil { + t.Fatalf("Expected no err, got '%v'", err) + } + // Change array to uint + arrayTypedData.Types["Foo"][0].Type = "uint[]" + arrayTypedData.Message["bar"] = []interface{}{ + big.NewInt(1955), + big.NewInt(108), + big.NewInt(44010), + } + _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) + if err != nil { + t.Fatalf("Expected no err, got '%v'", err) + } + + // Should not work with fixed-size arrays + arrayTypedData.Types["Foo"][0].Type = "uint[3]" + _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message) + if err == nil || err.Error() != "unknown type 'uint[3]'" { + t.Fatalf("Expected `unknown type 'uint[3]'`, got '%v'", err) + } } func TestCustomTypeAsArray(t *testing.T) { @@ -626,44 +685,45 @@ func TestCustomTypeAsArray(t *testing.T) { "type": "string" }, { - "name": "version", + "name": "version", "type": "string" }, { - "name": "chainId", + "name": "chainId", "type": "uint256" }, { - "name": "verifyingContract", + "name": "verifyingContract", "type": "address" } ], "Person": [ { - "name": "name", + "name": "name", "type": "string" }, { - "name": "wallet", + "name": "wallet", "type": "address" } ], "Person[]": [ { - "name": "baz", + "name": "baz", "type": "string" - }], + } + ], "Mail": [ { - "name": "from", + "name": "from", "type": "Person" }, { - "name": "to", + "name": "to", "type": "Person[]" }, { - "name": "contents", + "name": "contents", "type": "string" } ] @@ -677,8 +737,8 @@ func TestCustomTypeAsArray(t *testing.T) { }, "message": { "from": { - "name": "Cow", - "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" }, "to": {"baz": "foo"}, "contents": "Hello, Bob!" @@ -689,14 +749,26 @@ func TestCustomTypeAsArray(t *testing.T) { var malformedTypedData TypedData err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData) if err != nil { - t.Fatalf("unmarshalling failed %v", err) - } - err = malformedTypedData.Validate() - if err != nil { - t.Fatalf("Expected no error, got %v", err) + t.Fatalf("unmarshalling failed '%v'", err) } _, err = malformedTypedData.HashStruct("EIP712Domain", malformedTypedData.Domain.Map()) if err != nil { - t.Errorf("Expected no error, got %v", err) + t.Errorf("Expected no error, got '%v'", err) } } + +func TestFormatter(t *testing.T) { + + var d TypedData + err := json.Unmarshal([]byte(jsonTypedData), &d) + if err != nil { + t.Fatalf("unmarshalling failed '%v'", err) + } + formatted := d.Format() + for _, item := range formatted { + fmt.Printf("'%v'\n", item.Pprint(0)) + } + + j, _ := json.Marshal(formatted) + fmt.Printf("'%v'\n", string(j)) +}