Add utils for hashing and signing orders, update wrappers
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
};
|
||||
30
packages/contracts/src/utils/signing_utils.ts
Normal file
30
packages/contracts/src/utils/signing_utils.ts
Normal file
@@ -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`);
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user