Add transaction hash utils
This commit is contained in:
@@ -11,16 +11,16 @@ export const eip712Utils = {
|
||||
* @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 verifyingContractAddress The address of the verifying contract
|
||||
* @return A typed data object
|
||||
*/
|
||||
createTypedData: (
|
||||
primaryType: string,
|
||||
types: EIP712Types,
|
||||
message: EIP712Object,
|
||||
exchangeAddress: string,
|
||||
verifyingContractAddress: string,
|
||||
): EIP712TypedData => {
|
||||
assert.isETHAddressHex('exchangeAddress', exchangeAddress);
|
||||
assert.isETHAddressHex('verifyingContractAddress', verifyingContractAddress);
|
||||
assert.isString('primaryType', primaryType);
|
||||
const typedData = {
|
||||
types: {
|
||||
@@ -30,7 +30,7 @@ export const eip712Utils = {
|
||||
domain: {
|
||||
name: constants.EIP712_DOMAIN_NAME,
|
||||
version: constants.EIP712_DOMAIN_VERSION,
|
||||
verifyingContract: exchangeAddress,
|
||||
verifyingContract: verifyingContractAddress,
|
||||
},
|
||||
message,
|
||||
primaryType,
|
||||
@@ -60,7 +60,6 @@ export const eip712Utils = {
|
||||
* 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): EIP712TypedData => {
|
||||
|
||||
@@ -3,6 +3,7 @@ export { signatureUtils } from './signature_utils';
|
||||
export { generatePseudoRandomSalt } from './salt';
|
||||
export { assetDataUtils } from './asset_data_utils';
|
||||
export { marketUtils } from './market_utils';
|
||||
export { transactionHashUtils } from './transaction_hash';
|
||||
export { rateUtils } from './rate_utils';
|
||||
export { sortingUtils } from './sorting_utils';
|
||||
export { orderParsingUtils } from './parsing_utils';
|
||||
@@ -51,6 +52,7 @@ export {
|
||||
EIP712Object,
|
||||
EIP712ObjectValue,
|
||||
ZeroExTransaction,
|
||||
SignedZeroExTransaction,
|
||||
} from '@0x/types';
|
||||
export {
|
||||
OrderError,
|
||||
|
||||
46
packages/order-utils/src/transaction_hash.ts
Normal file
46
packages/order-utils/src/transaction_hash.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { schemas, SchemaValidator } from '@0x/json-schemas';
|
||||
import { SignedZeroExTransaction, ZeroExTransaction } from '@0x/types';
|
||||
import { signTypedDataUtils } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { assert } from './assert';
|
||||
import { eip712Utils } from './eip712_utils';
|
||||
|
||||
export const transactionHashUtils = {
|
||||
/**
|
||||
* Checks if the supplied hex encoded 0x transaction hash is valid.
|
||||
* Note: Valid means it has the expected format, not that a transaction with the transactionHash exists.
|
||||
* Use this method when processing transactionHashes submitted as user input.
|
||||
* @param transactionHash Hex encoded transactionHash.
|
||||
* @return Whether the supplied transactionHash has the expected format.
|
||||
*/
|
||||
isValidTransactionHash(transactionHash: string): boolean {
|
||||
// Since this method can be called to check if any arbitrary string conforms to an transactionHash's
|
||||
// format, we only assert that we were indeed passed a string.
|
||||
assert.isString('transactionHash', transactionHash);
|
||||
const schemaValidator = new SchemaValidator();
|
||||
const isValid = schemaValidator.validate(transactionHash, schemas.orderHashSchema).valid;
|
||||
return isValid;
|
||||
},
|
||||
/**
|
||||
* Computes the transactionHash for a supplied 0x transaction.
|
||||
* @param transaction An object that conforms to the ZeroExTransaction or SignedZeroExTransaction interface definitions.
|
||||
* @return Hex encoded string transactionHash from hashing the supplied order.
|
||||
*/
|
||||
getTransactionHashHex(transaction: ZeroExTransaction | SignedZeroExTransaction): string {
|
||||
assert.doesConformToSchema('transaction', transaction, schemas.zeroExTransactionSchema, [schemas.hexSchema]);
|
||||
const transactionHashBuff = transactionHashUtils.getTransactionHashBuffer(transaction);
|
||||
const transactionHashHex = `0x${transactionHashBuff.toString('hex')}`;
|
||||
return transactionHashHex;
|
||||
},
|
||||
/**
|
||||
* Computes the transactionHash for a supplied 0x transaction.
|
||||
* @param transaction An object that conforms to the ZeroExTransaction or SignedZeroExTransaction interface definitions.
|
||||
* @return A Buffer containing the resulting transactionHash from hashing the supplied 0x transaction.
|
||||
*/
|
||||
getTransactionHashBuffer(transaction: ZeroExTransaction | SignedZeroExTransaction): Buffer {
|
||||
const typedData = eip712Utils.createZeroExTransactionTypedData(transaction);
|
||||
const transactionHashBuff = signTypedDataUtils.generateTypedDataHash(typedData);
|
||||
return transactionHashBuff;
|
||||
},
|
||||
};
|
||||
56
packages/order-utils/test/transaction_hash_test.ts
Normal file
56
packages/order-utils/test/transaction_hash_test.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { ZeroExTransaction } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import 'mocha';
|
||||
|
||||
import { transactionHashUtils } from '../src';
|
||||
|
||||
import { constants } from '../src/constants';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
describe.only('0x transaction hashing', () => {
|
||||
describe('#getTransactionHashHex', () => {
|
||||
const expectedTransactionHash = '0x82c9bb2dcac4f868ec7a15c20ff6175cfc384c20ae6a872aa0342a840f108c2b';
|
||||
const fakeVerifyingContractAddress = '0x5e72914535f202659083db3a02c984188fa26e9f';
|
||||
const transaction: ZeroExTransaction = {
|
||||
verifyingContractAddress: fakeVerifyingContractAddress,
|
||||
signerAddress: constants.NULL_ADDRESS,
|
||||
salt: new BigNumber(0),
|
||||
data: constants.NULL_BYTES,
|
||||
};
|
||||
it('calculates the transaction hash', async () => {
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
expect(transactionHash).to.be.equal(expectedTransactionHash);
|
||||
});
|
||||
it('calculates the transaction hash if amounts are strings', async () => {
|
||||
// It's common for developers using javascript to provide the amounts
|
||||
// as strings. Since we eventually toString() the BigNumber
|
||||
// before encoding we should result in the same orderHash in this scenario
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex({
|
||||
...transaction,
|
||||
salt: '0',
|
||||
} as any);
|
||||
expect(transactionHash).to.be.equal(expectedTransactionHash);
|
||||
});
|
||||
});
|
||||
describe('#isValidTransactionHash', () => {
|
||||
it('returns false if the value is not a hex string', () => {
|
||||
const isValid = transactionHashUtils.isValidTransactionHash('not a hex');
|
||||
expect(isValid).to.be.false();
|
||||
});
|
||||
it('returns false if the length is wrong', () => {
|
||||
const isValid = transactionHashUtils.isValidTransactionHash('0xdeadbeef');
|
||||
expect(isValid).to.be.false();
|
||||
});
|
||||
it('returns true if order hash is correct', () => {
|
||||
const orderHashLength = 65;
|
||||
const isValid = transactionHashUtils.isValidTransactionHash(`0x${Array(orderHashLength).join('0')}`);
|
||||
expect(isValid).to.be.true();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user