Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

Commit

Permalink
Merge pull request #1102 from 0xProject/feature/0x.js/eip712-sign-typ…
Browse files Browse the repository at this point in the history
…ed-data

[0x.js][order-utils][web3-wrapper] Expose eth_signTypedData functionality for order signing
  • Loading branch information
dekz authored Oct 9, 2018
2 parents 3ac9dac + 75b9e63 commit 024bcf4
Show file tree
Hide file tree
Showing 53 changed files with 1,361 additions and 1,204 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"async-child-process": "^1.1.1",
"bundlesize": "^0.17.0",
"coveralls": "^3.0.0",
"ganache-cli": "6.1.3",
"ganache-cli": "6.1.8",
"lcov-result-merger": "^3.0.0",
"npm-cli-login": "^0.0.10",
"npm-run-all": "^4.1.2",
Expand Down
19 changes: 19 additions & 0 deletions packages/0x.js/CHANGELOG.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
[
{
"version": "2.0.0",
"changes": [
{
"note": "Add support for `eth_signTypedData`.",
"pr": 1102
},
{
"note":
"Added `MetamaskSubprovider` to handle inconsistencies in Metamask's signing JSON RPC endpoints.",
"pr": 1102
},
{
"note":
"Removed `SignerType` (including `SignerType.Metamask`). Please use the `MetamaskSubprovider` to wrap `web3.currentProvider`.",
"pr": 1102
}
]
},
{
"version": "1.0.8",
"changes": [
Expand Down
10 changes: 8 additions & 2 deletions packages/0x.js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,13 @@ export { OrderWatcher, OnOrderStateChangeCallback, OrderWatcherConfig } from '@0

export import Web3ProviderEngine = require('web3-provider-engine');

export { RPCSubprovider, Callback, JSONRPCRequestPayloadWithMethod, ErrorCallback } from '@0xproject/subproviders';
export {
RPCSubprovider,
Callback,
JSONRPCRequestPayloadWithMethod,
ErrorCallback,
MetamaskSubprovider,
} from '@0xproject/subproviders';

export { AbiDecoder } from '@0xproject/utils';

Expand All @@ -68,7 +74,6 @@ export {
OrderStateInvalid,
OrderState,
AssetProxyId,
SignerType,
ERC20AssetData,
ERC721AssetData,
SignatureType,
Expand All @@ -85,6 +90,7 @@ export {
JSONRPCRequestPayload,
JSONRPCResponsePayload,
JSONRPCErrorCallback,
JSONRPCResponseError,
LogEntry,
DecodedLogArgs,
LogEntryEvent,
Expand Down
1 change: 1 addition & 0 deletions packages/contract-wrappers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export {
JSONRPCRequestPayload,
JSONRPCResponsePayload,
JSONRPCErrorCallback,
JSONRPCResponseError,
AbiDefinition,
LogWithDecodedArgs,
FunctionAbi,
Expand Down
22 changes: 5 additions & 17 deletions packages/contract-wrappers/src/utils/transaction_encoder.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
import { schemas } from '@0xproject/json-schemas';
import { EIP712Schema, EIP712Types, eip712Utils } from '@0xproject/order-utils';
import { eip712Utils } from '@0xproject/order-utils';
import { Order, SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import { BigNumber, signTypedDataUtils } from '@0xproject/utils';
import _ = require('lodash');

import { ExchangeContract } from '../contract_wrappers/generated/exchange';

import { assert } from './assert';

const EIP712_ZEROEX_TRANSACTION_SCHEMA: EIP712Schema = {
name: 'ZeroExTransaction',
parameters: [
{ name: 'salt', type: EIP712Types.Uint256 },
{ name: 'signerAddress', type: EIP712Types.Address },
{ name: 'data', type: EIP712Types.Bytes },
],
};

/**
* Transaction Encoder. Transaction messages exist for the purpose of calling methods on the Exchange contract
* in the context of another address. For example, UserA can encode and sign a fillOrder transaction and UserB
Expand All @@ -41,12 +32,9 @@ export class TransactionEncoder {
signerAddress,
data,
};
const executeTransactionHashBuff = eip712Utils.structHash(
EIP712_ZEROEX_TRANSACTION_SCHEMA,
executeTransactionData,
);
const eip721MessageBuffer = eip712Utils.createEIP712Message(executeTransactionHashBuff, exchangeAddress);
const messageHex = `0x${eip721MessageBuffer.toString('hex')}`;
const typedData = eip712Utils.createZeroExTransactionTypedData(executeTransactionData, exchangeAddress);
const eip712MessageBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
const messageHex = `0x${eip712MessageBuffer.toString('hex')}`;
return messageHex;
}
/**
Expand Down
9 changes: 2 additions & 7 deletions packages/contract-wrappers/test/transaction_encoder_test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BlockchainLifecycle } from '@0xproject/dev-utils';
import { FillScenarios } from '@0xproject/fill-scenarios';
import { assetDataUtils, generatePseudoRandomSalt, orderHashUtils, signatureUtils } from '@0xproject/order-utils';
import { SignedOrder, SignerType } from '@0xproject/types';
import { SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import 'mocha';

Expand Down Expand Up @@ -80,12 +80,7 @@ describe('TransactionEncoder', () => {
): Promise<void> => {
const salt = generatePseudoRandomSalt();
const encodedTransaction = encoder.getTransactionHex(data, salt, signerAddress);
const signature = await signatureUtils.ecSignOrderHashAsync(
provider,
encodedTransaction,
signerAddress,
SignerType.Default,
);
const signature = await signatureUtils.ecSignHashAsync(provider, encodedTransaction, signerAddress);
txHash = await contractWrappers.exchange.executeTransactionAsync(
salt,
signerAddress,
Expand Down
18 changes: 1 addition & 17 deletions packages/contracts/test/exchange/libs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BlockchainLifecycle } from '@0xproject/dev-utils';
import { assetDataUtils, eip712Utils, orderHashUtils } from '@0xproject/order-utils';
import { assetDataUtils, orderHashUtils } from '@0xproject/order-utils';
import { SignedOrder } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
import * as chai from 'chai';
Expand Down Expand Up @@ -126,22 +126,6 @@ describe('Exchange libs', () => {
});

describe('LibOrder', () => {
describe('getOrderSchema', () => {
it('should output the correct order schema hash', async () => {
const orderSchema = await libs.getOrderSchemaHash.callAsync();
const schemaHashBuffer = orderHashUtils._getOrderSchemaBuffer();
const schemaHashHex = `0x${schemaHashBuffer.toString('hex')}`;
expect(schemaHashHex).to.be.equal(orderSchema);
});
});
describe('getDomainSeparatorSchema', () => {
it('should output the correct domain separator schema hash', async () => {
const domainSeparatorSchema = await libs.getDomainSeparatorSchemaHash.callAsync();
const domainSchemaBuffer = eip712Utils._getDomainSeparatorSchemaBuffer();
const schemaHashHex = `0x${domainSchemaBuffer.toString('hex')}`;
expect(schemaHashHex).to.be.equal(domainSeparatorSchema);
});
});
describe('getOrderHash', () => {
it('should output the correct orderHash', async () => {
signedOrder = await orderFactory.newSignedOrderAsync();
Expand Down
12 changes: 3 additions & 9 deletions packages/contracts/test/exchange/signature_validator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BlockchainLifecycle } from '@0xproject/dev-utils';
import { assetDataUtils, orderHashUtils, signatureUtils } from '@0xproject/order-utils';
import { RevertReason, SignatureType, SignedOrder, SignerType } from '@0xproject/types';
import { RevertReason, SignatureType, SignedOrder } from '@0xproject/types';
import * as chai from 'chai';
import { LogWithDecodedArgs } from 'ethereum-types';
import ethUtil = require('ethereumjs-util');
Expand Down Expand Up @@ -231,10 +231,7 @@ describe('MixinSignatureValidator', () => {
it('should return true when SignatureType=EthSign and signature is valid', async () => {
// Create EthSign signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(
orderHashHex,
SignerType.Default,
);
const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex);
const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
// Create 0x signature from EthSign signature
Expand All @@ -257,10 +254,7 @@ describe('MixinSignatureValidator', () => {
it('should return false when SignatureType=EthSign and signature is invalid', async () => {
// Create EthSign signature
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(
orderHashHex,
SignerType.Default,
);
const orderHashWithEthSignPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex);
const orderHashWithEthSignPrefixBuffer = ethUtil.toBuffer(orderHashWithEthSignPrefixHex);
const ecSignature = ethUtil.ecsign(orderHashWithEthSignPrefixBuffer, signerPrivateKey);
// Create 0x signature from EthSign signature
Expand Down
22 changes: 6 additions & 16 deletions packages/contracts/test/utils/transaction_factory.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
import { EIP712Schema, EIP712Types, eip712Utils, generatePseudoRandomSalt } from '@0xproject/order-utils';
import { eip712Utils, generatePseudoRandomSalt } from '@0xproject/order-utils';
import { SignatureType } from '@0xproject/types';
import { signTypedDataUtils } from '@0xproject/utils';
import * as ethUtil from 'ethereumjs-util';

import { signingUtils } from './signing_utils';
import { SignedTransaction } from './types';

const EIP712_ZEROEX_TRANSACTION_SCHEMA: EIP712Schema = {
name: 'ZeroExTransaction',
parameters: [
{ name: 'salt', type: EIP712Types.Uint256 },
{ name: 'signerAddress', type: EIP712Types.Address },
{ name: 'data', type: EIP712Types.Bytes },
],
};

export class TransactionFactory {
private readonly _signerBuff: Buffer;
private readonly _exchangeAddress: string;
Expand All @@ -31,12 +23,10 @@ export class TransactionFactory {
signerAddress,
data,
};
const executeTransactionHashBuff = eip712Utils.structHash(
EIP712_ZEROEX_TRANSACTION_SCHEMA,
executeTransactionData,
);
const txHash = eip712Utils.createEIP712Message(executeTransactionHashBuff, this._exchangeAddress);
const signature = signingUtils.signMessage(txHash, this._privateKey, signatureType);

const typedData = eip712Utils.createZeroExTransactionTypedData(executeTransactionData, this._exchangeAddress);
const eip712MessageBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
const signature = signingUtils.signMessage(eip712MessageBuffer, this._privateKey, signatureType);
const signedTx = {
exchangeAddress: this._exchangeAddress,
signature: `0x${signature.toString('hex')}`,
Expand Down
9 changes: 9 additions & 0 deletions packages/ethereum-types/CHANGELOG.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
[
{
"version": "1.1.0",
"changes": [
{
"note": "Add `JSONRPCResponseError` and error field on `JSONRPCResponsePayload`.",
"pr": 1102
}
]
},
{
"timestamp": 1538693146,
"version": "1.0.11",
Expand Down
6 changes: 6 additions & 0 deletions packages/ethereum-types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,16 @@ export interface JSONRPCRequestPayload {
jsonrpc: string;
}

export interface JSONRPCResponseError {
message: string;
code: number;
}

export interface JSONRPCResponsePayload {
result: any;
id: number;
jsonrpc: string;
error?: JSONRPCResponseError;
}

export interface AbstractBlock {
Expand Down
28 changes: 28 additions & 0 deletions packages/json-schemas/schemas/eip712_typed_data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const eip712TypedDataSchema = {
id: '/eip712TypedData',
type: 'object',
properties: {
types: {
type: 'object',
properties: {
EIP712Domain: { type: 'array' },
},
additionalProperties: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string' },
type: { type: 'string' },
},
required: ['name', 'type'],
},
},
required: ['EIP712Domain'],
},
primaryType: { type: 'string' },
domain: { type: 'object' },
message: { type: 'object' },
},
required: ['types', 'primaryType', 'domain', 'message'],
};
10 changes: 10 additions & 0 deletions packages/json-schemas/schemas/zero_ex_transaction_schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const zeroExTransactionSchema = {
id: '/zeroExTransactionSchema',
properties: {
data: { $ref: '/hexSchema' },
signerAddress: { $ref: '/addressSchema' },
salt: { $ref: '/numberSchema' },
},
required: ['data', 'salt', 'signerAddress'],
type: 'object',
};
4 changes: 4 additions & 0 deletions packages/json-schemas/src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { addressSchema, hexSchema, numberSchema } from '../schemas/basic_type_sc
import { blockParamSchema, blockRangeSchema } from '../schemas/block_range_schema';
import { callDataSchema } from '../schemas/call_data_schema';
import { ecSignatureParameterSchema, ecSignatureSchema } from '../schemas/ec_signature_schema';
import { eip712TypedDataSchema } from '../schemas/eip712_typed_data';
import { indexFilterValuesSchema } from '../schemas/index_filter_values_schema';
import { orderCancellationRequestsSchema } from '../schemas/order_cancel_schema';
import { orderFillOrKillRequestsSchema } from '../schemas/order_fill_or_kill_requests_schema';
Expand Down Expand Up @@ -31,6 +32,7 @@ import { relayerApiOrdersSchema } from '../schemas/relayer_api_orders_schema';
import { signedOrdersSchema } from '../schemas/signed_orders_schema';
import { tokenSchema } from '../schemas/token_schema';
import { jsNumber, txDataSchema } from '../schemas/tx_data_schema';
import { zeroExTransactionSchema } from '../schemas/zero_ex_transaction_schema';

export const schemas = {
numberSchema,
Expand All @@ -39,6 +41,7 @@ export const schemas = {
hexSchema,
ecSignatureParameterSchema,
ecSignatureSchema,
eip712TypedDataSchema,
indexFilterValuesSchema,
orderCancellationRequestsSchema,
orderFillOrKillRequestsSchema,
Expand Down Expand Up @@ -68,4 +71,5 @@ export const schemas = {
relayerApiOrdersChannelUpdateSchema,
relayerApiOrdersResponseSchema,
relayerApiAssetDataPairsSchema,
zeroExTransactionSchema,
};
18 changes: 18 additions & 0 deletions packages/order-utils/CHANGELOG.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
[
{
"version": "2.0.0",
"changes": [
{
"note":
"Added `ecSignOrderAsync` to first sign an order using `eth_signTypedData` and fallback to `eth_sign`.",
"pr": 1102
},
{
"note": "Added `ecSignTypedDataOrderAsync` to sign an order exclusively using `eth_signTypedData`.",
"pr": 1102
},
{
"note": "Rename `ecSignOrderHashAsync` to `ecSignHashAsync` removing `SignerType` parameter.",
"pr": 1102
}
]
},
{
"version": "1.0.7",
"changes": [
Expand Down
Loading

0 comments on commit 024bcf4

Please sign in to comment.