hash typed data (#1426)
* add HashTypedData to backend * add HashTypedData to backand, lib, and mobile * rename typeddata.Hash to typeddata.ValidateAndHash
This commit is contained in:
parent
b80a9f5aaa
commit
8fe14e8f23
|
@ -8,6 +8,7 @@ import (
|
|||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
|
@ -309,6 +310,16 @@ func (b *StatusBackend) SignTypedData(typed typeddata.TypedData, password string
|
|||
return hexutil.Bytes(sig), err
|
||||
}
|
||||
|
||||
// HashTypedData generates the hash of TypedData.
|
||||
func (b *StatusBackend) HashTypedData(typed typeddata.TypedData) (common.Hash, error) {
|
||||
chain := new(big.Int).SetUint64(b.StatusNode().Config().NetworkID)
|
||||
hash, err := typeddata.ValidateAndHash(typed, chain)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
return hash, err
|
||||
}
|
||||
|
||||
func (b *StatusBackend) getVerifiedWalletAccount(password string) (*account.SelectedExtKey, error) {
|
||||
selectedWalletAccount, err := b.accountManager.SelectedWalletAccount()
|
||||
if err != nil {
|
||||
|
|
|
@ -2,17 +2,20 @@ package api
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/status-im/status-go/account"
|
||||
"github.com/status-im/status-go/node"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/typeddata"
|
||||
"github.com/status-im/status-go/t/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -382,3 +385,48 @@ func TestStartStopMultipleTimes(t *testing.T) {
|
|||
require.NoError(t, backend.StartNode(config))
|
||||
require.NoError(t, backend.StopNode())
|
||||
}
|
||||
|
||||
func TestHashTypedData(t *testing.T) {
|
||||
backend := NewStatusBackend()
|
||||
config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
|
||||
require.NoError(t, err)
|
||||
err = backend.StartNode(config)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
require.NoError(t, backend.StopNode())
|
||||
}()
|
||||
|
||||
eip712Domain := "EIP712Domain"
|
||||
mytypes := typeddata.Types{
|
||||
eip712Domain: []typeddata.Field{
|
||||
{Name: "name", Type: "string"},
|
||||
{Name: "version", Type: "string"},
|
||||
{Name: "chainId", Type: "uint256"},
|
||||
{Name: "verifyingContract", Type: "address"},
|
||||
},
|
||||
"Text": []typeddata.Field{
|
||||
{Name: "body", Type: "string"},
|
||||
},
|
||||
}
|
||||
|
||||
domain := map[string]json.RawMessage{
|
||||
"name": json.RawMessage(`"Ether Text"`),
|
||||
"version": json.RawMessage(`"1"`),
|
||||
"chainId": json.RawMessage(fmt.Sprintf("%d", params.StatusChainNetworkID)),
|
||||
"verifyingContract": json.RawMessage(`"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"`),
|
||||
}
|
||||
msg := map[string]json.RawMessage{
|
||||
"body": json.RawMessage(`"Hello, Bob!"`),
|
||||
}
|
||||
|
||||
typed := typeddata.TypedData{
|
||||
Types: mytypes,
|
||||
PrimaryType: "Text",
|
||||
Domain: domain,
|
||||
Message: msg,
|
||||
}
|
||||
|
||||
hash, err := backend.HashTypedData(typed)
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, common.Hash{}, hash)
|
||||
}
|
||||
|
|
|
@ -485,6 +485,21 @@ func SignTypedData(data, password *C.char) *C.char {
|
|||
return C.CString(prepareJSONResponse(result.String(), err))
|
||||
}
|
||||
|
||||
// HashTypedData unmarshalls data into TypedData, validates it and hashes it.
|
||||
//export HashTypedData
|
||||
func HashTypedData(data *C.char) *C.char {
|
||||
var typed typeddata.TypedData
|
||||
err := json.Unmarshal([]byte(C.GoString(data)), &typed)
|
||||
if err != nil {
|
||||
return C.CString(prepareJSONResponseWithCode(nil, err, codeFailedParseParams))
|
||||
}
|
||||
if err := typed.Validate(); err != nil {
|
||||
return C.CString(prepareJSONResponseWithCode(nil, err, codeFailedParseParams))
|
||||
}
|
||||
result, err := statusBackend.HashTypedData(typed)
|
||||
return C.CString(prepareJSONResponse(result.String(), err))
|
||||
}
|
||||
|
||||
//StartCPUProfile runs pprof for cpu
|
||||
//export StartCPUProfile
|
||||
func StartCPUProfile(dataDir *C.char) *C.char {
|
||||
|
|
|
@ -369,6 +369,20 @@ func SignTypedData(data, password string) string {
|
|||
return prepareJSONResponse(result.String(), err)
|
||||
}
|
||||
|
||||
// HashTypedData unmarshalls data into TypedData, validates it and hashes it.
|
||||
func HashTypedData(data string) string {
|
||||
var typed typeddata.TypedData
|
||||
err := json.Unmarshal([]byte(data), &typed)
|
||||
if err != nil {
|
||||
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
||||
}
|
||||
if err := typed.Validate(); err != nil {
|
||||
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
|
||||
}
|
||||
result, err := statusBackend.HashTypedData(typed)
|
||||
return prepareJSONResponse(result.String(), err)
|
||||
}
|
||||
|
||||
// Recover unmarshals rpc params {signDataString, signedData} and passes
|
||||
// them onto backend.
|
||||
func Recover(rpcParams string) string {
|
||||
|
|
|
@ -19,6 +19,15 @@ var (
|
|||
int256Type, _ = abi.NewType("int256", nil)
|
||||
)
|
||||
|
||||
// ValidateAndHash generates a hash of TypedData and verifies that chainId in the typed data matches currently selected chain.
|
||||
func ValidateAndHash(typed TypedData, chain *big.Int) (common.Hash, error) {
|
||||
if err := typed.ValidateChainID(chain); err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
return encodeData(typed)
|
||||
}
|
||||
|
||||
// deps runs breadth-first traversal starting from target and collects all
|
||||
// found composite dependencies types into result slice. target always will be first
|
||||
// in the result array. all other dependencies are sorted alphabetically.
|
||||
|
|
|
@ -27,10 +27,7 @@ func encodeData(typed TypedData) (rst common.Hash, err error) {
|
|||
|
||||
// Sign TypedData with a given private key. Verify that chainId in the typed data matches currently selected chain.
|
||||
func Sign(typed TypedData, prv *ecdsa.PrivateKey, chain *big.Int) ([]byte, error) {
|
||||
if err := typed.ValidateChainID(chain); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hash, err := encodeData(typed)
|
||||
hash, err := ValidateAndHash(typed, chain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue