@ -18,6 +18,7 @@ package core
import (
import (
"context"
"context"
"encoding/json"
"errors"
"errors"
"fmt"
"fmt"
"mime"
"mime"
@ -135,11 +136,7 @@ func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType
req = & SignDataRequest { ContentType : mediaType , Rawdata : [ ] byte ( msg ) , Messages : messages , Hash : sighash }
req = & SignDataRequest { ContentType : mediaType , Rawdata : [ ] byte ( msg ) , Messages : messages , Hash : sighash }
case apitypes . ApplicationClique . Mime :
case apitypes . ApplicationClique . Mime :
// Clique is the Ethereum PoA standard
// Clique is the Ethereum PoA standard
stringData , ok := data . ( string )
cliqueData , err := fromHex ( data )
if ! ok {
return nil , useEthereumV , fmt . Errorf ( "input for %v must be an hex-encoded string" , apitypes . ApplicationClique . Mime )
}
cliqueData , err := hexutil . Decode ( stringData )
if err != nil {
if err != nil {
return nil , useEthereumV , err
return nil , useEthereumV , err
}
}
@ -167,27 +164,30 @@ func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType
// Clique uses V on the form 0 or 1
// Clique uses V on the form 0 or 1
useEthereumV = false
useEthereumV = false
req = & SignDataRequest { ContentType : mediaType , Rawdata : cliqueRlp , Messages : messages , Hash : sighash }
req = & SignDataRequest { ContentType : mediaType , Rawdata : cliqueRlp , Messages : messages , Hash : sighash }
case apitypes . DataTyped . Mime :
// EIP-712 conformant typed data
var err error
req , err = typedDataRequest ( data )
if err != nil {
return nil , useEthereumV , err
}
default : // also case TextPlain.Mime:
default : // also case TextPlain.Mime:
// Calculates an Ethereum ECDSA signature for:
// Calculates an Ethereum ECDSA signature for:
// hash = keccak256("\x19Ethereum Signed Message:\n${message length}${message}")
// hash = keccak256("\x19Ethereum Signed Message:\n${message length}${message}")
// We expect it to be a string
// We expect input to be a hex-encoded string
if stringData , ok := data . ( string ) ; ! ok {
textData , err := fromHex ( data )
return nil , useEthereumV , fmt . Errorf ( "input for text/plain must be an hex-encoded string" )
if err != nil {
} else {
return nil , useEthereumV , err
if textData , err := hexutil . Decode ( stringData ) ; err != nil {
return nil , useEthereumV , err
} else {
sighash , msg := accounts . TextAndHash ( textData )
messages := [ ] * apitypes . NameValueType {
{
Name : "message" ,
Typ : accounts . MimetypeTextPlain ,
Value : msg ,
} ,
}
req = & SignDataRequest { ContentType : mediaType , Rawdata : [ ] byte ( msg ) , Messages : messages , Hash : sighash }
}
}
}
sighash , msg := accounts . TextAndHash ( textData )
messages := [ ] * apitypes . NameValueType {
{
Name : "message" ,
Typ : accounts . MimetypeTextPlain ,
Value : msg ,
} ,
}
req = & SignDataRequest { ContentType : mediaType , Rawdata : [ ] byte ( msg ) , Messages : messages , Hash : sighash }
}
}
req . Address = addr
req . Address = addr
req . Meta = MetadataFromContext ( ctx )
req . Meta = MetadataFromContext ( ctx )
@ -233,20 +233,12 @@ func (api *SignerAPI) SignTypedData(ctx context.Context, addr common.MixedcaseAd
// - the signature preimage (hash)
// - the signature preimage (hash)
func ( api * SignerAPI ) signTypedData ( ctx context . Context , addr common . MixedcaseAddress ,
func ( api * SignerAPI ) signTypedData ( ctx context . Context , addr common . MixedcaseAddress ,
typedData apitypes . TypedData , validationMessages * apitypes . ValidationMessages ) ( hexutil . Bytes , hexutil . Bytes , error ) {
typedData apitypes . TypedData , validationMessages * apitypes . ValidationMessages ) ( hexutil . Bytes , hexutil . Bytes , error ) {
sighash , rawData , err := apitypes . TypedDataAndHash ( typedData )
req , err := typedDataRequest ( typedData )
if err != nil {
if err != nil {
return nil , nil , err
return nil , nil , err
}
}
messages , err := typedData . Format ( )
req . Address = addr
if err != nil {
req . Meta = MetadataFromContext ( ctx )
return nil , nil , err
}
req := & SignDataRequest {
ContentType : apitypes . DataTyped . Mime ,
Rawdata : [ ] byte ( rawData ) ,
Messages : messages ,
Hash : sighash ,
Address : addr }
if validationMessages != nil {
if validationMessages != nil {
req . Callinfo = validationMessages . Messages
req . Callinfo = validationMessages . Messages
}
}
@ -255,7 +247,46 @@ func (api *SignerAPI) signTypedData(ctx context.Context, addr common.MixedcaseAd
api . UI . ShowError ( err . Error ( ) )
api . UI . ShowError ( err . Error ( ) )
return nil , nil , err
return nil , nil , err
}
}
return signature , sighash , nil
return signature , req . Hash , nil
}
// fromHex tries to interpret the data as type string, and convert from
// hexadecimal to []byte
func fromHex ( data any ) ( [ ] byte , error ) {
if stringData , ok := data . ( string ) ; ok {
binary , err := hexutil . Decode ( stringData )
return binary , err
}
return nil , fmt . Errorf ( "wrong type %T" , data )
}
// typeDataRequest tries to convert the data into a SignDataRequest.
func typedDataRequest ( data any ) ( * SignDataRequest , error ) {
var typedData apitypes . TypedData
if td , ok := data . ( apitypes . TypedData ) ; ok {
typedData = td
} else { // Hex-encoded data
jsonData , err := fromHex ( data )
if err != nil {
return nil , err
}
if err = json . Unmarshal ( jsonData , & typedData ) ; err != nil {
return nil , err
}
}
messages , err := typedData . Format ( )
if err != nil {
return nil , err
}
sighash , rawData , err := apitypes . TypedDataAndHash ( typedData )
if err != nil {
return nil , err
}
return & SignDataRequest {
ContentType : apitypes . DataTyped . Mime ,
Rawdata : [ ] byte ( rawData ) ,
Messages : messages ,
Hash : sighash } , nil
}
}
// EcRecover recovers the address associated with the given sig.
// EcRecover recovers the address associated with the given sig.
@ -293,30 +324,20 @@ func UnmarshalValidatorData(data interface{}) (apitypes.ValidatorData, error) {
if ! ok {
if ! ok {
return apitypes . ValidatorData { } , errors . New ( "validator input is not a map[string]interface{}" )
return apitypes . ValidatorData { } , errors . New ( "validator input is not a map[string]interface{}" )
}
}
addr , ok := raw [ "address" ] . ( string )
addrBytes , err := fromHex ( raw [ "address" ] )
if ! ok {
return apitypes . ValidatorData { } , errors . New ( "validator address is not sent as a string" )
}
addrBytes , err := hexutil . Decode ( addr )
if err != nil {
if err != nil {
return apitypes . ValidatorData { } , err
return apitypes . ValidatorData { } , fmt . Errorf ( "validator address error: %w" , err )
}
}
if ! ok || len ( addrBytes ) == 0 {
if len ( addrBytes ) == 0 {
return apitypes . ValidatorData { } , errors . New ( "validator address is undefined" )
return apitypes . ValidatorData { } , errors . New ( "validator address is undefined" )
}
}
messageBytes , err := fromHex ( raw [ "message" ] )
message , ok := raw [ "message" ] . ( string )
if ! ok {
return apitypes . ValidatorData { } , errors . New ( "message is not sent as a string" )
}
messageBytes , err := hexutil . Decode ( message )
if err != nil {
if err != nil {
return apitypes . ValidatorData { } , err
return apitypes . ValidatorData { } , fmt . Errorf ( "message error: %w" , err )
}
}
if ! ok || len ( messageBytes ) == 0 {
if len ( messageBytes ) == 0 {
return apitypes . ValidatorData { } , errors . New ( "message is undefined" )
return apitypes . ValidatorData { } , errors . New ( "message is undefined" )
}
}
return apitypes . ValidatorData {
return apitypes . ValidatorData {
Address : common . BytesToAddress ( addrBytes ) ,
Address : common . BytesToAddress ( addrBytes ) ,
Message : messageBytes ,
Message : messageBytes ,