mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
Implemented latest recommendations
This commit is contained in:
parent
b0e872cd21
commit
8af9cda070
4 changed files with 388 additions and 192 deletions
|
|
@ -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"
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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"`
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 '<nil>' doesn't match type 'address'" {
|
||||
t.Errorf("Expected `provided data '<nil>' 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 '<nil>' doesn't match type 'address'" {
|
||||
t.Errorf("Expected `provided data '<nil>' 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))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue