Basic EIP712 encoder

This commit is contained in:
Jacob Evans
2018-06-07 16:03:14 -07:00
parent a59e9f024e
commit a8d328bfc9
3 changed files with 61 additions and 40 deletions

View File

@@ -26,21 +26,22 @@ export class TransactionFactory {
public newSignedTransaction(data: string, signatureType: SignatureType = SignatureType.EthSign): SignedTransaction { public newSignedTransaction(data: string, signatureType: SignatureType = SignatureType.EthSign): SignedTransaction {
const executeTransactionSchemaHashBuff = EIP712Utils.compileSchema(EIP712_EXECUTE_TRANSACTION_SCHEMA); const executeTransactionSchemaHashBuff = EIP712Utils.compileSchema(EIP712_EXECUTE_TRANSACTION_SCHEMA);
const salt = generatePseudoRandomSalt(); const salt = generatePseudoRandomSalt();
const dataHash = crypto.solSHA3([ethUtil.toBuffer(data)]); const signer = `0x${this._signerBuff.toString('hex')}`;
const executeTransactionDataHash = crypto.solSHA3([ const executeTransactionData = {
executeTransactionSchemaHashBuff,
salt, salt,
EIP712Utils.pad32Buffer(this._signerBuff), signer,
dataHash, data,
]); };
const txHash = EIP712Utils.createEIP712Message(executeTransactionDataHash, this._exchangeAddress); const executeTransactionHashBuff = EIP712Utils.structHash(
EIP712_EXECUTE_TRANSACTION_SCHEMA,
executeTransactionData,
);
const txHash = EIP712Utils.createEIP712Message(executeTransactionHashBuff, this._exchangeAddress);
const signature = signingUtils.signMessage(txHash, this._privateKey, signatureType); const signature = signingUtils.signMessage(txHash, this._privateKey, signatureType);
const signedTx = { const signedTx = {
exchangeAddress: this._exchangeAddress, exchangeAddress: this._exchangeAddress,
salt,
signer: `0x${this._signerBuff.toString('hex')}`,
data,
signature: `0x${signature.toString('hex')}`, signature: `0x${signature.toString('hex')}`,
...executeTransactionData,
}; };
return signedTx; return signedTx;
} }

View File

@@ -2,6 +2,7 @@ import { BigNumber } from '@0xproject/utils';
import ethUtil = require('ethereumjs-util'); import ethUtil = require('ethereumjs-util');
import * as _ from 'lodash'; import * as _ from 'lodash';
import { assetProxyUtils } from './asset_proxy_utils';
import { crypto } from './crypto'; import { crypto } from './crypto';
import { EIP712Schema } from './types'; import { EIP712Schema } from './types';
@@ -19,6 +20,14 @@ const EIP712_DOMAIN_SCHEMA: EIP712Schema = {
], ],
}; };
enum EIP712Types {
String = 'string',
Bytes = 'bytes',
Address = 'address',
Bytes32 = 'bytes32',
Uint256 = 'uint256',
}
export const EIP712Utils = { export const EIP712Utils = {
/** /**
* Compiles the EIP712Schema and returns the hash of the schema. * Compiles the EIP712Schema and returns the hash of the schema.
@@ -26,9 +35,7 @@ export const EIP712Utils = {
* @return The hash of the compiled schema * @return The hash of the compiled schema
*/ */
compileSchema(schema: EIP712Schema): Buffer { compileSchema(schema: EIP712Schema): Buffer {
const namedTypes = _.map(schema.parameters, parameter => `${parameter.type} ${parameter.name}`); const eip712Schema = EIP712Utils._encodeType(schema);
const namedTypesJoined = namedTypes.join(',');
const eip712Schema = `${schema.name}(${namedTypesJoined})`;
const eip712SchemaHashBuffer = crypto.solSHA3([eip712Schema]); const eip712SchemaHashBuffer = crypto.solSHA3([eip712Schema]);
return eip712SchemaHashBuffer; return eip712SchemaHashBuffer;
}, },
@@ -57,14 +64,44 @@ export const EIP712Utils = {
}, },
_getDomainSeparatorHashBuffer(exchangeAddress: string): Buffer { _getDomainSeparatorHashBuffer(exchangeAddress: string): Buffer {
const domainSeparatorSchemaBuffer = EIP712Utils._getDomainSeparatorSchemaBuffer(); const domainSeparatorSchemaBuffer = EIP712Utils._getDomainSeparatorSchemaBuffer();
const nameHash = crypto.solSHA3([EIP712_DOMAIN_NAME]); const encodedData = EIP712Utils._encodeData(EIP712_DOMAIN_SCHEMA, {
const versionHash = crypto.solSHA3([EIP712_DOMAIN_VERSION]); name: EIP712_DOMAIN_NAME,
const domainSeparatorHashBuff = crypto.solSHA3([ version: EIP712_DOMAIN_VERSION,
domainSeparatorSchemaBuffer, contract: exchangeAddress,
nameHash, });
versionHash, const domainSeparatorHashBuff2 = crypto.solSHA3([domainSeparatorSchemaBuffer, ...encodedData]);
EIP712Utils.pad32Address(exchangeAddress), return domainSeparatorHashBuff2;
]); },
return domainSeparatorHashBuff; _encodeType(schema: EIP712Schema): string {
const namedTypes = _.map(schema.parameters, ({ name, type }) => `${type} ${name}`);
const namedTypesJoined = namedTypes.join(',');
const encodedType = `${schema.name}(${namedTypesJoined})`;
return encodedType;
},
_encodeData(schema: EIP712Schema, data: { [key: string]: any }): any {
const encodedTypes = [];
const encodedValues = [];
for (const parameter of schema.parameters) {
const value = data[parameter.name];
if (parameter.type === EIP712Types.String || parameter.type === EIP712Types.Bytes) {
encodedTypes.push(EIP712Types.Bytes32);
encodedValues.push(crypto.solSHA3([ethUtil.toBuffer(value)]));
} else if (parameter.type === EIP712Types.Uint256) {
encodedTypes.push(EIP712Types.Uint256);
encodedValues.push(value);
} else if (parameter.type === EIP712Types.Address) {
encodedTypes.push(EIP712Types.Address);
encodedValues.push(EIP712Utils.pad32Address(value));
} else {
throw new Error(`Unable to encode ${parameter.type}`);
}
}
return encodedValues;
},
structHash(schema: EIP712Schema, data: { [key: string]: any }): Buffer {
const encodedData = EIP712Utils._encodeData(schema, data);
const schemaHash = EIP712Utils.compileSchema(schema);
const hashBuffer = crypto.solSHA3([schemaHash, ...encodedData]);
return hashBuffer;
}, },
}; };

View File

@@ -75,24 +75,7 @@ export const orderHashUtils = {
* @return The resulting orderHash from hashing the supplied order as a Buffer * @return The resulting orderHash from hashing the supplied order as a Buffer
*/ */
getOrderHashBuffer(order: SignedOrder | Order): Buffer { getOrderHashBuffer(order: SignedOrder | Order): Buffer {
const makerAssetDataHash = crypto.solSHA3([ethUtil.toBuffer(order.makerAssetData)]); const orderParamsHashBuff = EIP712Utils.structHash(EIP712_ORDER_SCHEMA, order);
const takerAssetDataHash = crypto.solSHA3([ethUtil.toBuffer(order.takerAssetData)]);
const orderParamsHashBuff = crypto.solSHA3([
orderHashUtils._getOrderSchemaBuffer(),
EIP712Utils.pad32Address(order.makerAddress),
EIP712Utils.pad32Address(order.takerAddress),
EIP712Utils.pad32Address(order.feeRecipientAddress),
EIP712Utils.pad32Address(order.senderAddress),
order.makerAssetAmount,
order.takerAssetAmount,
order.makerFee,
order.takerFee,
order.expirationTimeSeconds,
order.salt,
makerAssetDataHash,
takerAssetDataHash,
]);
const orderHashBuff = EIP712Utils.createEIP712Message(orderParamsHashBuff, order.exchangeAddress); const orderHashBuff = EIP712Utils.createEIP712Message(orderParamsHashBuff, order.exchangeAddress);
return orderHashBuff; return orderHashBuff;
}, },