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 #1576 from 0xProject/feat/transaction-hash
Browse files Browse the repository at this point in the history
Add transactionHashUtils to order-utils package
  • Loading branch information
abandeali1 authored Feb 5, 2019
2 parents 69c7c03 + af4ed0f commit b5eb47f
Show file tree
Hide file tree
Showing 23 changed files with 298 additions and 94 deletions.
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" },
"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

0 comments on commit b5eb47f

Please sign in to comment.