From 3ff8a319c5460caaf9edc1bea68e807fe0611aaa Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Wed, 7 Mar 2018 16:05:43 -0800 Subject: Add utils for hashing and signing orders, update wrappers --- .../protocol/Exchange/MixinWrapperFunctions.sol | 2 +- packages/contracts/src/utils/exchange_wrapper.ts | 16 +++-- packages/contracts/src/utils/order_factory.ts | 36 +++++----- packages/contracts/src/utils/order_utils.ts | 80 +++++++++++++++++++++ packages/contracts/src/utils/signed_order_utils.ts | 84 ---------------------- packages/contracts/src/utils/signing_utils.ts | 30 ++++++++ packages/contracts/src/utils/types.ts | 15 ++++ 7 files changed, 153 insertions(+), 110 deletions(-) create mode 100644 packages/contracts/src/utils/order_utils.ts delete mode 100644 packages/contracts/src/utils/signed_order_utils.ts create mode 100644 packages/contracts/src/utils/signing_utils.ts (limited to 'packages/contracts/src') diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol index 232765848..8e51404a7 100644 --- a/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol +++ b/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol @@ -19,7 +19,7 @@ pragma solidity ^0.4.19; pragma experimental ABIEncoderV2; -import './mixins/MExchangeCore.sol'; +import "./mixins/MExchangeCore.sol"; import "../../utils/SafeMath/SafeMath.sol"; /// @dev Consumes MExchangeCore diff --git a/packages/contracts/src/utils/exchange_wrapper.ts b/packages/contracts/src/utils/exchange_wrapper.ts index 7383f6b5d..04e6c2feb 100644 --- a/packages/contracts/src/utils/exchange_wrapper.ts +++ b/packages/contracts/src/utils/exchange_wrapper.ts @@ -8,7 +8,7 @@ import { ExchangeContract } from '../contract_wrappers/generated/exchange'; import { constants } from './constants'; import { formatters } from './formatters'; import { LogDecoder } from './log_decoder'; -import { signedOrderUtils } from './signed_order_utils'; +import { orderUtils } from './order_utils'; import { SignedOrder } from './types'; export class ExchangeWrapper { @@ -24,7 +24,7 @@ export class ExchangeWrapper { from: string, opts: { takerTokenFillAmount?: BigNumber } = {}, ): Promise { - const params = signedOrderUtils.createFill(signedOrder, opts.takerTokenFillAmount); + const params = orderUtils.createFill(signedOrder, opts.takerTokenFillAmount); const txHash = await this._exchange.fillOrder.sendTransactionAsync( params.order, params.takerTokenFillAmount, @@ -45,7 +45,7 @@ export class ExchangeWrapper { from: string, opts: { takerTokenCancelAmount?: BigNumber } = {}, ): Promise { - const params = signedOrderUtils.createCancel(signedOrder, opts.takerTokenCancelAmount); + const params = orderUtils.createCancel(signedOrder, opts.takerTokenCancelAmount); const txHash = await this._exchange.cancelOrder.sendTransactionAsync( params.order, params.takerTokenCancelAmount, @@ -65,7 +65,7 @@ export class ExchangeWrapper { from: string, opts: { takerTokenFillAmount?: BigNumber } = {}, ): Promise { - const params = signedOrderUtils.createFill(signedOrder, opts.takerTokenFillAmount); + const params = orderUtils.createFill(signedOrder, opts.takerTokenFillAmount); const txHash = await this._exchange.fillOrKillOrder.sendTransactionAsync( params.order, params.takerTokenFillAmount, @@ -165,14 +165,14 @@ export class ExchangeWrapper { return tx; } public async getOrderHashAsync(signedOrder: SignedOrder): Promise { - const order = signedOrderUtils.getOrderStruct(signedOrder); + const order = orderUtils.getOrderStruct(signedOrder); const orderHash = await this._exchange.getOrderHash.callAsync(order); return orderHash; } public async isValidSignatureAsync(signedOrder: SignedOrder): Promise { const isValidSignature = await this._exchange.isValidSignature.callAsync( + orderUtils.getOrderHashHex(signedOrder), signedOrder.makerAddress, - signedOrderUtils.getOrderHashHex(signedOrder), signedOrder.signature, ); return isValidSignature; @@ -195,6 +195,10 @@ export class ExchangeWrapper { ); return partialAmount; } + public async getFilledTakerTokenAmountAsync(orderHashHex: string): Promise { + const filledAmount = new BigNumber(await this._exchange.filled.callAsync(orderHashHex)); + return filledAmount; + } } function wrapLogBigNumbers(log: any): any { diff --git a/packages/contracts/src/utils/order_factory.ts b/packages/contracts/src/utils/order_factory.ts index d5c3a9544..3f09cedf3 100644 --- a/packages/contracts/src/utils/order_factory.ts +++ b/packages/contracts/src/utils/order_factory.ts @@ -1,37 +1,35 @@ -import { Order, ZeroEx } from '0x.js'; +import { ZeroEx } from '0x.js'; import { BigNumber } from '@0xproject/utils'; -import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; -import { signedOrderUtils } from './signed_order_utils'; -import { DefaultOrderParams, SignedOrder } from './types'; +import { orderUtils } from './order_utils'; +import { signingUtils } from './signing_utils'; +import { DefaultOrderParams, SignatureType, SignedOrder, UnsignedOrder } from './types'; export class OrderFactory { - private _defaultOrderParams: Partial; - private _zeroEx: ZeroEx; - constructor(zeroEx: ZeroEx, defaultOrderParams: Partial) { + private _defaultOrderParams: Partial; + private _secretKey: Buffer; + constructor(secretKey: Buffer, defaultOrderParams: Partial) { this._defaultOrderParams = defaultOrderParams; - this._zeroEx = zeroEx; + this._secretKey = secretKey; } - public async newSignedOrderAsync(customOrderParams: Partial = {}): Promise { + public newSignedOrder( + customOrderParams: Partial = {}, + signatureType: SignatureType = SignatureType.Ecrecover, + ): SignedOrder { const randomExpiration = new BigNumber(Math.floor((Date.now() + Math.random() * 100000000000) / 1000)); const order = ({ - expirationTimestampSeconds: randomExpiration, + expirationTimeSeconds: randomExpiration, salt: ZeroEx.generatePseudoRandomSalt(), takerAddress: ZeroEx.NULL_ADDRESS, ...this._defaultOrderParams, ...customOrderParams, - } as any) as SignedOrder; - const orderHashHex = signedOrderUtils.getOrderHashHex(order); - const shouldAddPersonalMessagePrefix = false; - const ecSignature = await this._zeroEx.signOrderHashAsync( - orderHashHex, - order.makerAddress, - shouldAddPersonalMessagePrefix, - ); + } as any) as UnsignedOrder; + const orderHashBuff = orderUtils.getOrderHashBuff(order); + const signature = signingUtils.signMessage(orderHashBuff, this._secretKey, signatureType); const signedOrder = { ...order, - ecSignature, + signature: `0x${signature.toString('hex')}`, }; return signedOrder; } diff --git a/packages/contracts/src/utils/order_utils.ts b/packages/contracts/src/utils/order_utils.ts new file mode 100644 index 000000000..513d0087e --- /dev/null +++ b/packages/contracts/src/utils/order_utils.ts @@ -0,0 +1,80 @@ +import { BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import ethUtil = require('ethereumjs-util'); +import * as _ from 'lodash'; + +import { crypto } from './crypto'; +import { OrderStruct, SignatureType, SignedOrder, UnsignedOrder } from './types'; + +export const orderUtils = { + createFill: (signedOrder: SignedOrder, takerTokenFillAmount?: BigNumber) => { + const fill = { + order: orderUtils.getOrderStruct(signedOrder), + takerTokenFillAmount: takerTokenFillAmount || signedOrder.takerTokenAmount, + signature: signedOrder.signature, + }; + return fill; + }, + createCancel(signedOrder: SignedOrder, takerTokenCancelAmount?: BigNumber) { + const cancel = { + order: orderUtils.getOrderStruct(signedOrder), + takerTokenCancelAmount: takerTokenCancelAmount || signedOrder.takerTokenAmount, + }; + return cancel; + }, + getOrderStruct(signedOrder: SignedOrder): OrderStruct { + const orderStruct = { + makerAddress: signedOrder.makerAddress, + takerAddress: signedOrder.takerAddress, + makerTokenAddress: signedOrder.makerTokenAddress, + takerTokenAddress: signedOrder.takerTokenAddress, + feeRecipientAddress: signedOrder.feeRecipientAddress, + makerTokenAmount: signedOrder.makerTokenAmount, + takerTokenAmount: signedOrder.takerTokenAmount, + makerFeeAmount: signedOrder.makerFeeAmount, + takerFeeAmount: signedOrder.takerFeeAmount, + expirationTimeSeconds: signedOrder.expirationTimeSeconds, + salt: signedOrder.salt, + }; + return orderStruct; + }, + getOrderHashBuff(order: SignedOrder | UnsignedOrder): Buffer { + const orderSchemaHashBuff = crypto.solSHA3([ + 'address exchangeAddress', + 'address makerAddress', + 'address takerAddress', + 'address makerTokenAddress', + 'address takerTokenAddress', + 'address feeRecipientAddress', + 'uint256 makerTokenAmount', + 'uint256 takerTokenAmount', + 'uint256 makerFeeAmount', + 'uint256 takerFeeAmount', + 'uint256 expirationTimeSeconds', + 'uint256 salt', + ]); + const orderSchemaHashHex = `0x${orderSchemaHashBuff.toString('hex')}`; + const orderHashBuff = crypto.solSHA3([ + order.exchangeAddress, + order.makerAddress, + order.takerAddress, + order.makerTokenAddress, + order.takerTokenAddress, + order.feeRecipientAddress, + order.makerTokenAmount, + order.takerTokenAmount, + order.makerFeeAmount, + order.takerFeeAmount, + order.expirationTimeSeconds, + order.salt, + ]); + const orderHashHex = `0x${orderHashBuff.toString('hex')}`; + const prefixedOrderHashBuff = crypto.solSHA3([new BigNumber(orderSchemaHashHex), new BigNumber(orderHashHex)]); + return prefixedOrderHashBuff; + }, + getOrderHashHex(order: SignedOrder | UnsignedOrder): string { + const orderHashBuff = orderUtils.getOrderHashBuff(order); + const orderHashHex = `0x${orderHashBuff.toString('hex')}`; + return orderHashHex; + }, +}; diff --git a/packages/contracts/src/utils/signed_order_utils.ts b/packages/contracts/src/utils/signed_order_utils.ts deleted file mode 100644 index 1d9096ee4..000000000 --- a/packages/contracts/src/utils/signed_order_utils.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { BigNumber } from '@0xproject/utils'; -import { Web3Wrapper } from '@0xproject/web3-wrapper'; -import ethUtil = require('ethereumjs-util'); -import * as _ from 'lodash'; - -import { crypto } from './crypto'; -import { OrderStruct, SignatureType, SignedOrder } from './types'; - -export const signedOrderUtils = { - createFill: (signedOrder: SignedOrder, takerTokenFillAmount?: BigNumber) => { - const fill = { - order: signedOrderUtils.getOrderStruct(signedOrder), - takerTokenFillAmount: takerTokenFillAmount || signedOrder.takerTokenAmount, - signature: signedOrder.signature, - }; - return fill; - }, - createCancel(signedOrder: SignedOrder, takerTokenCancelAmount?: BigNumber) { - const cancel = { - order: signedOrderUtils.getOrderStruct(signedOrder), - takerTokenCancelAmount: takerTokenCancelAmount || signedOrder.takerTokenAmount, - }; - return cancel; - }, - getOrderStruct(signedOrder: SignedOrder): OrderStruct { - const orderStruct = { - makerAddress: signedOrder.makerAddress, - takerAddress: signedOrder.takerAddress, - makerTokenAddress: signedOrder.makerTokenAddress, - takerTokenAddress: signedOrder.takerTokenAddress, - feeRecipientAddress: signedOrder.feeRecipientAddress, - makerTokenAmount: signedOrder.makerTokenAmount, - takerTokenAmount: signedOrder.takerTokenAmount, - makerFeeAmount: signedOrder.makerFeeAmount, - takerFeeAmount: signedOrder.takerFeeAmount, - expirationTimeSeconds: signedOrder.expirationTimeSeconds, - salt: signedOrder.salt, - }; - return orderStruct; - }, - getOrderHashHex(signedOrder: SignedOrder): string { - const orderSchemaHashBuff = crypto.solSHA3([ - 'address exchangeAddress', - 'address makerAddress', - 'address takerAddress', - 'address makerTokenAddress', - 'address takerTokenAddress', - 'address feeRecipientAddress', - 'uint256 makerTokenAmount', - 'uint256 takerTokenAmount', - 'uint256 makerFeeAmount', - 'uint256 takerFeeAmount', - 'uint256 expirationTimestampSeconds', - 'uint256 salt', - ]); - const orderSchemaHashHex = `0x${orderSchemaHashBuff.toString('hex')}`; - const orderHashBuff = crypto.solSHA3([ - signedOrder.exchangeAddress, - signedOrder.makerAddress, - signedOrder.takerAddress, - signedOrder.makerTokenAddress, - signedOrder.takerTokenAddress, - signedOrder.feeRecipientAddress, - signedOrder.makerTokenAmount, - signedOrder.takerTokenAmount, - signedOrder.makerFeeAmount, - signedOrder.takerFeeAmount, - signedOrder.expirationTimeSeconds, - signedOrder.salt, - ]); - const orderHashHex = `0x${orderHashBuff.toString('hex')}`; - const prefixedOrderHashBuff = crypto.solSHA3([new BigNumber(orderSchemaHashHex), new BigNumber(orderHashHex)]); - const prefixedOrderHashHex = `0x${prefixedOrderHashBuff.toString('hex')}`; - return prefixedOrderHashHex; - }, - getSignatureType(signature: string): SignatureType { - const signatureBuff = new Buffer(signature); - const signatureType = signatureBuff[0]; - if (!_.has(SignatureType, signatureType)) { - throw new Error(`${signatureType} is not a valid signature type`); - } - return signatureType; - }, -}; diff --git a/packages/contracts/src/utils/signing_utils.ts b/packages/contracts/src/utils/signing_utils.ts new file mode 100644 index 000000000..21b69619c --- /dev/null +++ b/packages/contracts/src/utils/signing_utils.ts @@ -0,0 +1,30 @@ +import * as ethUtil from 'ethereumjs-util'; + +import { SignatureType } from './types'; + +export const signingUtils = { + signMessage(message: Buffer, secretKey: Buffer, signatureType: SignatureType): Buffer { + if (signatureType === SignatureType.Ecrecover) { + const prefixedMessage = ethUtil.hashPersonalMessage(message); + const ecSignature = ethUtil.ecsign(prefixedMessage, secretKey); + const signature = Buffer.concat([ + ethUtil.toBuffer(signatureType), + ethUtil.toBuffer(ecSignature.v), + ecSignature.r, + ecSignature.s, + ]); + return signature; + } else if (signatureType === SignatureType.EIP712) { + const ecSignature = ethUtil.ecsign(message, secretKey); + const signature = Buffer.concat([ + ethUtil.toBuffer(signatureType), + ethUtil.toBuffer(ecSignature.v), + ecSignature.r, + ecSignature.s, + ]); + return signature; + } else { + throw new Error(`${signatureType} is not a valid signature type`); + } + }, +}; diff --git a/packages/contracts/src/utils/types.ts b/packages/contracts/src/utils/types.ts index 5075c7bf5..b16925825 100644 --- a/packages/contracts/src/utils/types.ts +++ b/packages/contracts/src/utils/types.ts @@ -138,6 +138,21 @@ export interface OrderStruct { salt: BigNumber; } +export interface UnsignedOrder { + exchangeAddress: string; + makerAddress: string; + takerAddress: string; + makerTokenAddress: string; + takerTokenAddress: string; + feeRecipientAddress: string; + makerTokenAmount: BigNumber; + takerTokenAmount: BigNumber; + makerFeeAmount: BigNumber; + takerFeeAmount: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; +} + export enum SignatureType { Illegal, Invalid, -- cgit