Skip to content

Commit

Permalink
Simplify function type signatures
Browse files Browse the repository at this point in the history
The type signatures of many public functions were complex and
misleading. This was primarily due to the widespread use of the types
`TypedData` and `TypedMessage<T>`, which where inappropriate in most of
the places they were used.

The `TypedMessage<T>` type is used by the `signTypedData` function when
the version is 'V3' or 'V4'. All references to this type outside of V3
and V4 of `signTypedData` have been removed. This also resulted in the
`T` generic parameter being removed from many functions.

The `TypedData` type didn't represent the actual type signature of any
function, yet it was used everywhere. It has been replaced with
`unknown` in the cases where no specific type is expected, and with
`EIP712TypedData[]` for `V1` of `signTypeData`.
  • Loading branch information
Gudahtt committed Sep 9, 2021
1 parent 6cf6849 commit cba08fd
Showing 1 changed file with 30 additions and 31 deletions.
61 changes: 30 additions & 31 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { intToHex, isHexString, stripHexPrefix } from 'ethjs-util';

import { padWithZeroes } from './utils';

export type TypedData = string | EIP712TypedData | EIP712TypedData[];

interface EIP712TypedData {
name: string;
type: string;
Expand Down Expand Up @@ -288,7 +286,7 @@ function hashType(
* @returns {Object} - typed message object with only allowed fields
*/
function sanitizeData<T extends MessageTypes>(
data: TypedData | TypedMessage<T>,
data: TypedMessage<T>,
): TypedMessage<T> {
const sanitizedData: Partial<TypedMessage<T>> = {};
for (const key in TYPED_MESSAGE_SCHEMA.properties) {
Expand All @@ -314,7 +312,7 @@ function sanitizeData<T extends MessageTypes>(
* @returns {Buffer} - The hash of the typed message.
*/
function eip712Hash<T extends MessageTypes>(
typedData: TypedData | TypedMessage<T>,
typedData: TypedMessage<T>,
version: Version,
): Buffer {
const sanitizedData = sanitizeData(typedData);
Expand Down Expand Up @@ -407,9 +405,9 @@ export function normalize(input: number | string): string {
* @param msgParams - The message parameters. Currently includes just the message data.
* @param msgParams.data - The data to sign.
*/
export function personalSign<T extends MessageTypes>(
export function personalSign(
privateKey: Buffer,
msgParams: MsgParams<TypedData | TypedMessage<T>>,
msgParams: MsgParams<unknown>,
): string {
const message = legacyToBuffer(msgParams.data);
const msgHash = ethUtil.hashPersonalMessage(message);
Expand All @@ -427,8 +425,8 @@ export function personalSign<T extends MessageTypes>(
* @param msgParams.sig - The signature for the message.
* @returns The address of the message signer.
*/
export function recoverPersonalSignature<T extends MessageTypes>(
msgParams: SignedMsgParams<TypedData | TypedMessage<T>>,
export function recoverPersonalSignature(
msgParams: SignedMsgParams<unknown>,
): string {
const publicKey = getPublicKeyFor(msgParams);
const sender = ethUtil.publicToAddress(publicKey);
Expand All @@ -445,9 +443,7 @@ export function recoverPersonalSignature<T extends MessageTypes>(
* @param msgParams.sig - The signature for the message.
* @returns The public key of the message signer.
*/
export function extractPublicKey<T extends MessageTypes>(
msgParams: SignedMsgParams<TypedData | TypedMessage<T>>,
): string {
export function extractPublicKey(msgParams: SignedMsgParams<unknown>): string {
const publicKey = getPublicKeyFor(msgParams);
return `0x${publicKey.toString('hex')}`;
}
Expand All @@ -474,9 +470,9 @@ export function typedSignatureHash(typedData: EIP712TypedData[]): string {
* @param version - The type of encryption to use.
* @returns The encrypted data.
*/
export function encrypt<T extends MessageTypes>(
export function encrypt(
receiverPublicKey: string,
msgParams: MsgParams<TypedData | TypedMessage<T>>,
msgParams: MsgParams<unknown>,
version: string,
): EthEncryptedData {
switch (version) {
Expand Down Expand Up @@ -535,9 +531,9 @@ export function encrypt<T extends MessageTypes>(
* @param version - The type of encryption to use.
* @returns The encrypted data.
*/
export function encryptSafely<T extends MessageTypes>(
export function encryptSafely(
receiverPublicKey: string,
msgParams: MsgParams<TypedData | TypedMessage<T>>,
msgParams: MsgParams<unknown>,
version: string,
): EthEncryptedData {
const DEFAULT_PADDING_LENGTH = 2 ** 11;
Expand Down Expand Up @@ -675,15 +671,17 @@ export function getEncryptionPublicKey(privateKey: string): string {
* @param version - The signing version to use.
* @returns The signature
*/
export function signTypedData<T extends MessageTypes>(
export function signTypedData<V extends Version, T extends MessageTypes>(
privateKey: Buffer,
msgParams: MsgParams<TypedData | TypedMessage<T>>,
version: Version,
msgParams: V extends 'V1'
? MsgParams<EIP712TypedData[]>
: MsgParams<TypedMessage<T>>,
version: V,
): string {
const messageHash =
version === 'V1'
? _typedSignatureHash(msgParams.data)
: TypedDataUtils.eip712Hash(msgParams.data, version);
? _typedSignatureHash(msgParams.data as EIP712TypedData[])
: TypedDataUtils.eip712Hash(msgParams.data as TypedMessage<T>, version);
const sig = ethUtil.ecsign(messageHash, privateKey);
return concatSig(ethUtil.toBuffer(sig.v), sig.r, sig.s);
}
Expand All @@ -698,22 +696,25 @@ export function signTypedData<T extends MessageTypes>(
* @param version - The signing version to use.
* @returns The address of the signer.
*/
export function recoverTypedSignature<T extends MessageTypes>(
msgParams: SignedMsgParams<TypedData | TypedMessage<T>>,
version: Version,
export function recoverTypedSignature<
V extends Version,
T extends MessageTypes,
>(
msgParams: V extends 'V1'
? SignedMsgParams<EIP712TypedData[]>
: SignedMsgParams<TypedMessage<T>>,
version: V,
): string {
const messageHash =
version === 'V1'
? _typedSignatureHash(msgParams.data)
: TypedDataUtils.eip712Hash(msgParams.data, version);
? _typedSignatureHash(msgParams.data as EIP712TypedData[])
: TypedDataUtils.eip712Hash(msgParams.data as TypedMessage<T>, version);
const publicKey = recoverPublicKey(messageHash, msgParams.sig);
const sender = ethUtil.publicToAddress(publicKey);
return ethUtil.bufferToHex(sender);
}

function _typedSignatureHash<T extends MessageTypes>(
typedData: TypedData | TypedMessage<T>,
): Buffer {
function _typedSignatureHash(typedData: EIP712TypedData[]): Buffer {
const error = new Error('Expect argument to be non-empty array');
if (
typeof typedData !== 'object' ||
Expand Down Expand Up @@ -754,9 +755,7 @@ function recoverPublicKey(hash: Buffer, sig: string): Buffer {
return ethUtil.ecrecover(hash, sigParams.v, sigParams.r, sigParams.s);
}

function getPublicKeyFor<T extends MessageTypes>(
msgParams: MsgParams<TypedData | TypedMessage<T>>,
): Buffer {
function getPublicKeyFor(msgParams: MsgParams<unknown>): Buffer {
const message = legacyToBuffer(msgParams.data);
const msgHash = ethUtil.hashPersonalMessage(message);
return recoverPublicKey(msgHash, msgParams.sig);
Expand Down

0 comments on commit cba08fd

Please sign in to comment.