Skip to content

Commit

Permalink
signer/core: extended support for EIP-712 array types (ethereum#30620)
Browse files Browse the repository at this point in the history
This change updates the EIP-712 implementation to resolve [ethereum#30619](ethereum#30619).

The test cases have been repurposed from the ethers.js [repository](https://github.com/ethers-io/ethers.js/blob/main/testcases/typed-data.json.gz), but have been updated to remove tests that don't have a valid domain separator; EIP-712 messages without a domain separator are not supported by geth.

---------

Co-authored-by: Martin Holst Swende <martin@swende.se>
  • Loading branch information
naveen-imtb and holiman authored Nov 8, 2024
1 parent a6037d0 commit 5b78aef
Show file tree
Hide file tree
Showing 4 changed files with 6,272 additions and 71 deletions.
71 changes: 37 additions & 34 deletions signer/core/apitypes/signed_data_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@ package apitypes

import (
"bytes"
"encoding/json"
"fmt"
"math/big"
"os"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestBytesPadding(t *testing.T) {
Expand Down Expand Up @@ -244,45 +250,42 @@ func TestConvertAddressDataToSlice(t *testing.T) {
func TestTypedDataArrayValidate(t *testing.T) {
t.Parallel()

typedData := TypedData{
Types: Types{
"BulkOrder": []Type{
// Should be able to accept fixed size arrays
{Name: "tree", Type: "OrderComponents[2][2]"},
},
"OrderComponents": []Type{
{Name: "offerer", Type: "address"},
{Name: "amount", Type: "uint8"},
},
"EIP712Domain": []Type{
{Name: "name", Type: "string"},
{Name: "version", Type: "string"},
{Name: "chainId", Type: "uint8"},
{Name: "verifyingContract", Type: "address"},
},
},
PrimaryType: "BulkOrder",
Domain: TypedDataDomain{
VerifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
},
Message: TypedDataMessage{},
type testDataInput struct {
Name string `json:"name"`
Domain TypedDataDomain `json:"domain"`
PrimaryType string `json:"primaryType"`
Types Types `json:"types"`
Message TypedDataMessage `json:"data"`
Digest string `json:"digest"`
}
fc, err := os.ReadFile("./testdata/typed-data.json")
require.NoError(t, err, "error reading test data file")

if err := typedData.validate(); err != nil {
t.Errorf("expected typed data to pass validation, got: %v", err)
}
var tests []testDataInput
err = json.Unmarshal(fc, &tests)
require.NoError(t, err, "error unmarshalling test data file contents")

// Should be able to accept dynamic arrays
typedData.Types["BulkOrder"][0].Type = "OrderComponents[]"
for _, tc := range tests {
t.Run(tc.Name, func(t *testing.T) {
t.Parallel()

if err := typedData.validate(); err != nil {
t.Errorf("expected typed data to pass validation, got: %v", err)
}
td := TypedData{
Types: tc.Types,
PrimaryType: tc.PrimaryType,
Domain: tc.Domain,
Message: tc.Message,
}

domainSeparator, tErr := td.HashStruct("EIP712Domain", td.Domain.Map())
assert.NoError(t, tErr, "failed to hash domain separator: %v", tErr)

messageHash, tErr := td.HashStruct(td.PrimaryType, td.Message)
assert.NoError(t, tErr, "failed to hash message: %v", tErr)

// Should be able to accept standard types
typedData.Types["BulkOrder"][0].Type = "OrderComponents"
digest := crypto.Keccak256Hash([]byte(fmt.Sprintf("%s%s%s", "\x19\x01", string(domainSeparator), string(messageHash))))
assert.Equal(t, tc.Digest, digest.String(), "digest doesn't not match")

if err := typedData.validate(); err != nil {
t.Errorf("expected typed data to pass validation, got: %v", err)
assert.NoError(t, td.validate(), "validation failed", tErr)
})
}
}
Loading

0 comments on commit 5b78aef

Please sign in to comment.