diff --git a/x/auth/tx/eip191.go b/x/auth/tx/eip191.go new file mode 100644 index 0000000000000..6f7f26d60ba8c --- /dev/null +++ b/x/auth/tx/eip191.go @@ -0,0 +1,64 @@ +package tx + +import ( + "fmt" + "strconv" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + "github.com/cosmos/cosmos-sdk/x/auth/signing" +) + +const EIP191MessagePrefix = "\x19Ethereum Signed Message:\n" + +const eip191NonCriticalFieldsError = "protobuf transaction contains unknown non-critical fields. This is a transaction malleability issue and SIGN_MODE_EIP_191 cannot be used." + +// SignModeEIP191Handler defines the SIGN_MODE_DIRECT SignModeHandler +type SignModeEIP191Handler struct{} + +var _ signing.SignModeHandler = SignModeEIP191Handler{} + +// DefaultMode implements SignModeHandler.DefaultMode +func (SignModeEIP191Handler) DefaultMode() signingtypes.SignMode { + return signingtypes.SignMode_SIGN_MODE_EIP_191 +} + +// Modes implements SignModeHandler.Modes +func (SignModeEIP191Handler) Modes() []signingtypes.SignMode { + return []signingtypes.SignMode{signingtypes.SignMode_SIGN_MODE_EIP_191} +} + +// GetSignBytes implements SignModeHandler.GetSignBytes +func (SignModeEIP191Handler) GetSignBytes(mode signingtypes.SignMode, data signing.SignerData, tx sdk.Tx) ([]byte, error) { + if mode != signingtypes.SignMode_SIGN_MODE_EIP_191 { + return nil, fmt.Errorf("expected %s, got %s", signingtypes.SignMode_SIGN_MODE_EIP_191, mode) + } + + protoTx, ok := tx.(*wrapper) + if !ok { + return nil, fmt.Errorf("can only handle a protobuf Tx, got %T", tx) + } + + if protoTx.txBodyHasUnknownNonCriticals { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, eip191NonCriticalFieldsError) + } + + body := protoTx.tx.Body + + if len(body.ExtensionOptions) != 0 || len(body.NonCriticalExtensionOptions) != 0 { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "SignMode_SIGN_MODE_EIP_191 does not support protobuf extension options.") + } + + aminoJSONBz := legacytx.StdSignBytes( + data.ChainID, data.AccountNumber, data.Sequence, protoTx.GetTimeoutHeight(), + legacytx.StdFee{Amount: protoTx.GetFee(), Gas: protoTx.GetGas()}, + tx.GetMsgs(), protoTx.GetMemo(), protoTx.GetTip(), + ) + + return append(append( + []byte(EIP191MessagePrefix), + []byte(strconv.Itoa(len(aminoJSONBz)))..., + ), aminoJSONBz...), nil +} diff --git a/x/auth/tx/mode_handler.go b/x/auth/tx/mode_handler.go index 19e34df49a241..598b0e755cc53 100644 --- a/x/auth/tx/mode_handler.go +++ b/x/auth/tx/mode_handler.go @@ -12,6 +12,7 @@ var DefaultSignModes = []signingtypes.SignMode{ signingtypes.SignMode_SIGN_MODE_DIRECT, signingtypes.SignMode_SIGN_MODE_DIRECT_AUX, signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, + signingtypes.SignMode_SIGN_MODE_EIP_191, } // makeSignModeHandler returns the default protobuf SignModeHandler supporting @@ -31,6 +32,8 @@ func makeSignModeHandler(modes []signingtypes.SignMode) signing.SignModeHandler handlers[i] = signModeLegacyAminoJSONHandler{} case signingtypes.SignMode_SIGN_MODE_DIRECT_AUX: handlers[i] = signModeDirectAuxHandler{} + case signingtypes.SignMode_SIGN_MODE_EIP_191: + handlers[i] = SignModeEIP191Handler{} default: panic(fmt.Errorf("unsupported sign mode %+v", mode)) }