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

Add transactionHashUtils to order-utils package #1576

Merged
merged 9 commits into from
Feb 5, 2019
5 changes: 2 additions & 3 deletions contracts/exchange/test/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ import {
OrderFactory,
orderUtils,
provider,
SignedTransaction,
TransactionFactory,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
import { OrderWithoutExchangeAddress, RevertReason, SignedOrder } from '@0x/types';
import { OrderWithoutExchangeAddress, RevertReason, SignedOrder, SignedZeroExTransaction } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import * as _ from 'lodash';
Expand All @@ -41,7 +40,7 @@ describe('Exchange transactions', () => {

let erc20Balances: ERC20BalancesByOwner;
let signedOrder: SignedOrder;
let signedTx: SignedTransaction;
let signedTx: SignedZeroExTransaction;
let orderWithoutExchangeAddress: OrderWithoutExchangeAddress;
let orderFactory: OrderFactory;
let makerTransactionFactory: TransactionFactory;
Expand Down
13 changes: 3 additions & 10 deletions contracts/exchange/test/utils/exchange_wrapper.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import { artifacts as erc20Artifacts } from '@0x/contracts-erc20';
import { artifacts as erc721Artifacts } from '@0x/contracts-erc721';
import {
FillResults,
formatters,
LogDecoder,
OrderInfo,
orderUtils,
SignedTransaction,
} from '@0x/contracts-test-utils';
import { SignedOrder } from '@0x/types';
import { FillResults, formatters, LogDecoder, OrderInfo, orderUtils } from '@0x/contracts-test-utils';
import { SignedOrder, SignedZeroExTransaction } from '@0x/types';
import { AbiEncoder, BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { MethodAbi, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
Expand Down Expand Up @@ -206,7 +199,7 @@ export class ExchangeWrapper {
return tx;
}
public async executeTransactionAsync(
signedTx: SignedTransaction,
signedTx: SignedZeroExTransaction,
from: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const txHash = await this._exchange.executeTransaction.sendTransactionAsync(
Expand Down
4 changes: 4 additions & 0 deletions contracts/test-utils/CHANGELOG.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
{
"note": "Upgrade the bignumber.js to v8.0.2",
"pr": 1517
},
{
"note": "Import `ZeroExTransaction` type instead of using type defined in this package",
"pr": 1576
}
],
"timestamp": 1549373905
Expand Down
1 change: 0 additions & 1 deletion contracts/test-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export {
MarketBuyOrders,
MarketSellOrders,
ERC721TokenIdsByOwner,
SignedTransaction,
OrderStatus,
AllowanceAmountScenario,
AssetDataScenario,
Expand Down
26 changes: 13 additions & 13 deletions contracts/test-utils/src/transaction_factory.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { eip712Utils, generatePseudoRandomSalt } from '@0x/order-utils';
import { SignatureType } from '@0x/types';
import { signTypedDataUtils } from '@0x/utils';
import { generatePseudoRandomSalt, transactionHashUtils } from '@0x/order-utils';
import { SignatureType, SignedZeroExTransaction } from '@0x/types';
import * as ethUtil from 'ethereumjs-util';

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

export class TransactionFactory {
private readonly _signerBuff: Buffer;
Expand All @@ -15,23 +13,25 @@ export class TransactionFactory {
this._exchangeAddress = exchangeAddress;
this._signerBuff = ethUtil.privateToAddress(this._privateKey);
}
public newSignedTransaction(data: string, signatureType: SignatureType = SignatureType.EthSign): SignedTransaction {
public newSignedTransaction(
data: string,
signatureType: SignatureType = SignatureType.EthSign,
): SignedZeroExTransaction {
const salt = generatePseudoRandomSalt();
const signerAddress = `0x${this._signerBuff.toString('hex')}`;
const executeTransactionData = {
const transaction = {
salt,
signerAddress,
data,
verifyingContractAddress: this._exchangeAddress,
};

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,
const transactionHashBuffer = transactionHashUtils.getTransactionHashBuffer(transaction);
const signature = signingUtils.signMessage(transactionHashBuffer, this._privateKey, signatureType);
const signedTransaction = {
...transaction,
signature: `0x${signature.toString('hex')}`,
...executeTransactionData,
};
return signedTx;
return signedTransaction;
}
}
8 changes: 0 additions & 8 deletions contracts/test-utils/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,6 @@ export enum ContractName {
BalanceThresholdFilter = 'BalanceThresholdFilter',
}

export interface SignedTransaction {
exchangeAddress: string;
salt: BigNumber;
signerAddress: string;
data: string;
signature: string;
}

export interface TransferAmountsByMatchOrders {
// Left Maker
amountBoughtByLeftMaker: BigNumber;
Expand Down
10 changes: 9 additions & 1 deletion packages/contract-wrappers/CHANGELOG.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
[
{
"version": "6.0.1",
"version": "7.0.0",
"changes": [
{
"note": "Fix OrderValidatorWrapper constructor to use the correct address",
"pr": 1568
},
{
"note": "Use new `ZeroExTransaction` interface",
"pr": 1576
},
{
"note": "Rename `getTransactionHex` to `getTransactionHashHex`",
"pr": 1576
}
],
"timestamp": 1549373905
Expand Down
19 changes: 9 additions & 10 deletions packages/contract-wrappers/src/utils/transaction_encoder.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ExchangeContract } from '@0x/abi-gen-wrappers';

import { schemas } from '@0x/json-schemas';
import { eip712Utils } from '@0x/order-utils';
import { transactionHashUtils } from '@0x/order-utils';
import { Order, SignedOrder } from '@0x/types';
import { BigNumber, signTypedDataUtils } from '@0x/utils';
import { BigNumber } from '@0x/utils';
import _ = require('lodash');

import { assert } from './assert';
Expand All @@ -19,23 +19,22 @@ export class TransactionEncoder {
this._exchangeInstance = exchangeInstance;
}
/**
* Encodes the transaction data for use with the Exchange contract.
* Hashes the transaction data for use with the Exchange contract.
* @param data The ABI Encoded 0x Exchange method. I.e fillOrder
* @param salt A random value to provide uniqueness and prevent replay attacks.
* @param signerAddress The address which will sign this transaction.
* @return An unsigned hex encoded transaction for use in 0x Exchange executeTransaction.
* @return The hash of the 0x transaction.
*/
public getTransactionHex(data: string, salt: BigNumber, signerAddress: string): string {
public getTransactionHashHex(data: string, salt: BigNumber, signerAddress: string): string {
const exchangeAddress = this._getExchangeContract().address;
const executeTransactionData = {
const transaction = {
verifyingContractAddress: exchangeAddress,
salt,
signerAddress,
data,
};
const typedData = eip712Utils.createZeroExTransactionTypedData(executeTransactionData, exchangeAddress);
const eip712MessageBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
const messageHex = `0x${eip712MessageBuffer.toString('hex')}`;
return messageHex;
const hashHex = transactionHashUtils.getTransactionHashHex(transaction);
return hashHex;
}
/**
* Encodes a fillOrder transaction.
Expand Down
4 changes: 2 additions & 2 deletions packages/contract-wrappers/test/transaction_encoder_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ describe('TransactionEncoder', () => {
signerAddress: string = takerAddress,
): Promise<void> => {
const salt = generatePseudoRandomSalt();
const encodedTransaction = encoder.getTransactionHex(data, salt, signerAddress);
const signature = await signatureUtils.ecSignHashAsync(provider, encodedTransaction, signerAddress);
const transactionHash = encoder.getTransactionHashHex(data, salt, signerAddress);
const signature = await signatureUtils.ecSignHashAsync(provider, transactionHash, signerAddress);
txHash = await contractWrappers.exchange.executeTransactionAsync(
salt,
signerAddress,
Expand Down
4 changes: 4 additions & 0 deletions packages/json-schemas/CHANGELOG.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
{
"note": "Upgrade the bignumber.js to v8.0.2",
"pr": 1517
},
{
"note": "Add `verifyingContractAddress` to `zeroExTransactionSchema`",
"pr": 1576
}
],
"timestamp": 1549373905
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"id": "/zeroExTransactionSchema",
"properties": {
"verifyingContractAddress": { "$ref": "/addressSchema" },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required? If so, you should add it to the required array below.

"data": { "$ref": "/hexSchema" },
"signerAddress": { "$ref": "/addressSchema" },
"salt": { "$ref": "/wholeNumberSchema" }
},
"required": ["data", "salt", "signerAddress"],
"required": ["verifyingContractAddress", "data", "salt", "signerAddress"],
"type": "object"
}
17 changes: 17 additions & 0 deletions packages/order-utils/CHANGELOG.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
[
{
"version": "5.0.0",
"changes": [
{
"note": "Add `transactionHashUtils`",
"pr": 1576
},
{
"note": "Refactor `eip712Utils` to allow custom domain params",
"pr": 1576
},
{
"note": "Export constant EIP712 params",
"pr": 1576
}
]
},
{
"version": "4.0.0",
"changes": [
Expand Down
10 changes: 5 additions & 5 deletions packages/order-utils/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,17 @@ export const constants = {
SELECTOR_CHAR_LENGTH_WITH_PREFIX: 10,
INFINITE_TIMESTAMP_SEC: new BigNumber(2524604400), // Close to infinite
ZERO_AMOUNT: new BigNumber(0),
EIP712_DOMAIN_NAME: '0x Protocol',
EIP712_DOMAIN_VERSION: '2',
EIP712_DOMAIN_SCHEMA: {
EXCHANGE_DOMAIN_NAME: '0x Protocol',
EXCHANGE_DOMAIN_VERSION: '2',
DEFAULT_DOMAIN_SCHEMA: {
name: 'EIP712Domain',
parameters: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'verifyingContract', type: 'address' },
],
},
EIP712_ORDER_SCHEMA: {
EXCHANGE_ORDER_SCHEMA: {
name: 'Order',
parameters: [
{ name: 'makerAddress', type: 'address' },
Expand All @@ -95,7 +95,7 @@ export const constants = {
{ name: 'takerAssetData', type: 'bytes' },
],
},
EIP712_ZEROEX_TRANSACTION_SCHEMA: {
EXCHANGE_ZEROEX_TRANSACTION_SCHEMA: {
name: 'ZeroExTransaction',
parameters: [
{ name: 'salt', type: 'uint256' },
Expand Down
55 changes: 35 additions & 20 deletions packages/order-utils/src/eip712_utils.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,49 @@
import { assert } from '@0x/assert';
import { schemas } from '@0x/json-schemas';
import { EIP712Object, EIP712TypedData, EIP712Types, Order, ZeroExTransaction } from '@0x/types';
import {
EIP712DomainWithDefaultSchema,
EIP712Object,
EIP712TypedData,
EIP712Types,
Order,
ZeroExTransaction,
} from '@0x/types';
import * as _ from 'lodash';

import { constants } from './constants';

export const DEFAULT_DOMAIN_SCHEMA = constants.DEFAULT_DOMAIN_SCHEMA;
export const EXCHANGE_DOMAIN_NAME = constants.EXCHANGE_DOMAIN_NAME;
export const EXCHANGE_DOMAIN_VERSION = constants.EXCHANGE_DOMAIN_VERSION;
export const EXCHANGE_ORDER_SCHEMA = constants.EXCHANGE_ORDER_SCHEMA;
export const EXCHANGE_ZEROEX_TRANSACTION_SCHEMA = constants.EXCHANGE_ZEROEX_TRANSACTION_SCHEMA;

export const eip712Utils = {
/**
* Creates a EIP712TypedData object specific to the 0x protocol for use with signTypedData.
* @param primaryType The primary type found in message
* @param types The additional types for the data in message
* @param message The contents of the message
* @param exchangeAddress The address of the exchange contract
* @param domain Domain containing a name (optional), version (optional), and verifying contract address
* @return A typed data object
*/
createTypedData: (
primaryType: string,
types: EIP712Types,
message: EIP712Object,
exchangeAddress: string,
domain: EIP712DomainWithDefaultSchema,
): EIP712TypedData => {
assert.isETHAddressHex('exchangeAddress', exchangeAddress);
assert.isETHAddressHex('verifyingContractAddress', domain.verifyingContractAddress);
assert.isString('primaryType', primaryType);
const typedData = {
types: {
EIP712Domain: constants.EIP712_DOMAIN_SCHEMA.parameters,
EIP712Domain: DEFAULT_DOMAIN_SCHEMA.parameters,
...types,
},
domain: {
name: constants.EIP712_DOMAIN_NAME,
version: constants.EIP712_DOMAIN_VERSION,
verifyingContract: exchangeAddress,
name: _.isUndefined(domain.name) ? EXCHANGE_DOMAIN_NAME : domain.name,
version: _.isUndefined(domain.version) ? EXCHANGE_DOMAIN_VERSION : domain.version,
verifyingContract: domain.verifyingContractAddress,
},
message,
primaryType,
Expand All @@ -48,35 +61,37 @@ export const eip712Utils = {
const normalizedOrder = _.mapValues(order, value => {
return !_.isString(value) ? value.toString() : value;
});
const domain = {
verifyingContractAddress: order.exchangeAddress,
};
const typedData = eip712Utils.createTypedData(
constants.EIP712_ORDER_SCHEMA.name,
{ Order: constants.EIP712_ORDER_SCHEMA.parameters },
EXCHANGE_ORDER_SCHEMA.name,
{ Order: EXCHANGE_ORDER_SCHEMA.parameters },
normalizedOrder,
order.exchangeAddress,
domain,
);
return typedData;
},
/**
* Creates an ExecuteTransaction EIP712TypedData object for use with signTypedData and
* 0x Exchange executeTransaction.
* @param ZeroExTransaction the 0x transaction
* @param exchangeAddress The address of the exchange contract
* @return A typed data object
*/
createZeroExTransactionTypedData: (
zeroExTransaction: ZeroExTransaction,
exchangeAddress: string,
): EIP712TypedData => {
assert.isETHAddressHex('exchangeAddress', exchangeAddress);
createZeroExTransactionTypedData: (zeroExTransaction: ZeroExTransaction): EIP712TypedData => {
assert.isETHAddressHex('verifyingContractAddress', zeroExTransaction.verifyingContractAddress);
assert.doesConformToSchema('zeroExTransaction', zeroExTransaction, schemas.zeroExTransactionSchema);
const normalizedTransaction = _.mapValues(zeroExTransaction, value => {
return !_.isString(value) ? value.toString() : value;
});
const domain = {
verifyingContractAddress: zeroExTransaction.verifyingContractAddress,
};
const typedData = eip712Utils.createTypedData(
constants.EIP712_ZEROEX_TRANSACTION_SCHEMA.name,
{ ZeroExTransaction: constants.EIP712_ZEROEX_TRANSACTION_SCHEMA.parameters },
EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.name,
{ ZeroExTransaction: EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.parameters },
normalizedTransaction,
exchangeAddress,
domain,
);
return typedData;
},
Expand Down
Loading