diff options
author | Amir Bandeali <abandeali1@gmail.com> | 2018-03-08 08:05:43 +0800 |
---|---|---|
committer | Amir Bandeali <abandeali1@gmail.com> | 2018-04-21 04:56:16 +0800 |
commit | 3ff8a319c5460caaf9edc1bea68e807fe0611aaa (patch) | |
tree | 77c255e42d1dfcedad7f1692c9467e28cd9a3802 | |
parent | cd8f8e1e4acc00e9e31265050456a4c98d79a7d4 (diff) | |
download | dexon-0x-contracts-3ff8a319c5460caaf9edc1bea68e807fe0611aaa.tar.gz dexon-0x-contracts-3ff8a319c5460caaf9edc1bea68e807fe0611aaa.tar.zst dexon-0x-contracts-3ff8a319c5460caaf9edc1bea68e807fe0611aaa.zip |
Add utils for hashing and signing orders, update wrappers
-rw-r--r-- | packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol | 2 | ||||
-rw-r--r-- | packages/contracts/src/utils/exchange_wrapper.ts | 16 | ||||
-rw-r--r-- | packages/contracts/src/utils/order_factory.ts | 36 | ||||
-rw-r--r-- | packages/contracts/src/utils/order_utils.ts (renamed from packages/contracts/src/utils/signed_order_utils.ts) | 50 | ||||
-rw-r--r-- | packages/contracts/src/utils/signing_utils.ts | 30 | ||||
-rw-r--r-- | packages/contracts/src/utils/types.ts | 15 |
6 files changed, 96 insertions, 53 deletions
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<TransactionReceiptWithDecodedLogs> { - 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<TransactionReceiptWithDecodedLogs> { - 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<TransactionReceiptWithDecodedLogs> { - 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<string> { - 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<boolean> { 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<BigNumber> { + 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<Order>; - private _zeroEx: ZeroEx; - constructor(zeroEx: ZeroEx, defaultOrderParams: Partial<Order>) { + private _defaultOrderParams: Partial<UnsignedOrder>; + private _secretKey: Buffer; + constructor(secretKey: Buffer, defaultOrderParams: Partial<UnsignedOrder>) { this._defaultOrderParams = defaultOrderParams; - this._zeroEx = zeroEx; + this._secretKey = secretKey; } - public async newSignedOrderAsync(customOrderParams: Partial<Order> = {}): Promise<SignedOrder> { + public newSignedOrder( + customOrderParams: Partial<UnsignedOrder> = {}, + 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/signed_order_utils.ts b/packages/contracts/src/utils/order_utils.ts index 1d9096ee4..513d0087e 100644 --- a/packages/contracts/src/utils/signed_order_utils.ts +++ b/packages/contracts/src/utils/order_utils.ts @@ -4,12 +4,12 @@ import ethUtil = require('ethereumjs-util'); import * as _ from 'lodash'; import { crypto } from './crypto'; -import { OrderStruct, SignatureType, SignedOrder } from './types'; +import { OrderStruct, SignatureType, SignedOrder, UnsignedOrder } from './types'; -export const signedOrderUtils = { +export const orderUtils = { createFill: (signedOrder: SignedOrder, takerTokenFillAmount?: BigNumber) => { const fill = { - order: signedOrderUtils.getOrderStruct(signedOrder), + order: orderUtils.getOrderStruct(signedOrder), takerTokenFillAmount: takerTokenFillAmount || signedOrder.takerTokenAmount, signature: signedOrder.signature, }; @@ -17,7 +17,7 @@ export const signedOrderUtils = { }, createCancel(signedOrder: SignedOrder, takerTokenCancelAmount?: BigNumber) { const cancel = { - order: signedOrderUtils.getOrderStruct(signedOrder), + order: orderUtils.getOrderStruct(signedOrder), takerTokenCancelAmount: takerTokenCancelAmount || signedOrder.takerTokenAmount, }; return cancel; @@ -38,7 +38,7 @@ export const signedOrderUtils = { }; return orderStruct; }, - getOrderHashHex(signedOrder: SignedOrder): string { + getOrderHashBuff(order: SignedOrder | UnsignedOrder): Buffer { const orderSchemaHashBuff = crypto.solSHA3([ 'address exchangeAddress', 'address makerAddress', @@ -50,35 +50,31 @@ export const signedOrderUtils = { 'uint256 takerTokenAmount', 'uint256 makerFeeAmount', 'uint256 takerFeeAmount', - 'uint256 expirationTimestampSeconds', + 'uint256 expirationTimeSeconds', '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, + 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)]); - const prefixedOrderHashHex = `0x${prefixedOrderHashBuff.toString('hex')}`; - return prefixedOrderHashHex; + return prefixedOrderHashBuff; }, - 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; + 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/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, |