diff options
-rw-r--r-- | packages/contracts/util/exchange_wrapper.ts | 59 | ||||
-rw-r--r-- | packages/contracts/util/formatters.ts | 34 | ||||
-rw-r--r-- | packages/contracts/util/order.ts | 105 | ||||
-rw-r--r-- | packages/contracts/util/signed_order_utils.ts | 10 | ||||
-rw-r--r-- | packages/contracts/util/types.ts | 8 |
5 files changed, 148 insertions, 68 deletions
diff --git a/packages/contracts/util/exchange_wrapper.ts b/packages/contracts/util/exchange_wrapper.ts index f016067fe..14d603f58 100644 --- a/packages/contracts/util/exchange_wrapper.ts +++ b/packages/contracts/util/exchange_wrapper.ts @@ -18,22 +18,16 @@ export class ExchangeWrapper { public async fillOrderAsync( signedOrder: SignedOrder, from: string, - opts: { - fillTakerTokenAmount?: BigNumber; - shouldThrowOnInsufficientBalanceOrAllowance?: boolean; - } = {}, + opts: { takerTokenFillAmount?: BigNumber } = {}, ): Promise<TransactionReceiptWithDecodedLogs> { - const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; const params = signedOrderUtils.createFill( signedOrder, - shouldThrowOnInsufficientBalanceOrAllowance, - opts.fillTakerTokenAmount, + opts.takerTokenFillAmount, ); const txHash = await this._exchange.fillOrder.sendTransactionAsync( params.orderAddresses, params.orderValues, - params.fillTakerTokenAmount, - params.shouldThrowOnInsufficientBalanceOrAllowance, + params.takerTokenFillAmount, params.v, params.r, params.s, @@ -47,13 +41,13 @@ export class ExchangeWrapper { public async cancelOrderAsync( signedOrder: SignedOrder, from: string, - opts: { cancelTakerTokenAmount?: BigNumber } = {}, + opts: { takerTokenCancelAmount?: BigNumber } = {}, ): Promise<TransactionReceiptWithDecodedLogs> { - const params = signedOrderUtils.createCancel(signedOrder, opts.cancelTakerTokenAmount); + const params = signedOrderUtils.createCancel(signedOrder, opts.takerTokenCancelAmount); const txHash = await this._exchange.cancelOrder.sendTransactionAsync( params.orderAddresses, params.orderValues, - params.cancelTakerTokenAmount, + params.takerTokenCancelAmount, { from }, ); const tx = await this._zeroEx.awaitTransactionMinedAsync(txHash); @@ -64,18 +58,16 @@ export class ExchangeWrapper { public async fillOrKillOrderAsync( signedOrder: SignedOrder, from: string, - opts: { fillTakerTokenAmount?: BigNumber } = {}, + opts: { takerTokenFillAmount?: BigNumber } = {}, ): Promise<TransactionReceiptWithDecodedLogs> { - const shouldThrowOnInsufficientBalanceOrAllowance = true; const params = signedOrderUtils.createFill( signedOrder, - shouldThrowOnInsufficientBalanceOrAllowance, - opts.fillTakerTokenAmount, + opts.takerTokenFillAmount, ); const txHash = await this._exchange.fillOrKillOrder.sendTransactionAsync( params.orderAddresses, params.orderValues, - params.fillTakerTokenAmount, + params.takerTokenFillAmount, params.v, params.r, params.s, @@ -90,21 +82,18 @@ export class ExchangeWrapper { orders: SignedOrder[], from: string, opts: { - fillTakerTokenAmounts?: BigNumber[]; + takerTokenFillAmounts?: BigNumber[]; shouldThrowOnInsufficientBalanceOrAllowance?: boolean; } = {}, ): Promise<TransactionReceiptWithDecodedLogs> { - const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; const params = formatters.createBatchFill( orders, - shouldThrowOnInsufficientBalanceOrAllowance, - opts.fillTakerTokenAmounts, + opts.takerTokenFillAmounts, ); const txHash = await this._exchange.batchFillOrders.sendTransactionAsync( params.orderAddresses, params.orderValues, - params.fillTakerTokenAmounts, - params.shouldThrowOnInsufficientBalanceOrAllowance, + params.takerTokenFillAmounts, params.v, params.r, params.s, @@ -118,18 +107,16 @@ export class ExchangeWrapper { public async batchFillOrKillOrdersAsync( orders: SignedOrder[], from: string, - opts: { fillTakerTokenAmounts?: BigNumber[]; shouldThrowOnInsufficientBalanceOrAllowance?: boolean } = {}, + opts: { takerTokenFillAmounts?: BigNumber[] } = {}, ): Promise<TransactionReceiptWithDecodedLogs> { - const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; const params = formatters.createBatchFill( orders, - shouldThrowOnInsufficientBalanceOrAllowance, - opts.fillTakerTokenAmounts, + opts.takerTokenFillAmounts, ); const txHash = await this._exchange.batchFillOrKillOrders.sendTransactionAsync( params.orderAddresses, params.orderValues, - params.fillTakerTokenAmounts, + params.takerTokenFillAmounts, params.v, params.r, params.s, @@ -140,22 +127,19 @@ export class ExchangeWrapper { _.each(tx.logs, log => wrapLogBigNumbers(log)); return tx; } - public async fillOrdersUpToAsync( + public async marketFillOrdersAsync( orders: SignedOrder[], from: string, - opts: { fillTakerTokenAmount: BigNumber; shouldThrowOnInsufficientBalanceOrAllowance?: boolean }, + opts: { takerTokenFillAmount: BigNumber }, ): Promise<TransactionReceiptWithDecodedLogs> { - const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; - const params = formatters.createFillUpTo( + const params = formatters.createMarketFillOrders( orders, - shouldThrowOnInsufficientBalanceOrAllowance, - opts.fillTakerTokenAmount, + opts.takerTokenFillAmount, ); - const txHash = await this._exchange.fillOrdersUpTo.sendTransactionAsync( + const txHash = await this._exchange.marketFillOrders.sendTransactionAsync( params.orderAddresses, params.orderValues, - params.fillTakerTokenAmount, - params.shouldThrowOnInsufficientBalanceOrAllowance, + params.takerTokenFillAmount, params.v, params.r, params.s, @@ -184,7 +168,6 @@ export class ExchangeWrapper { return tx; } public async getOrderHashAsync(signedOrder: SignedOrder): Promise<string> { - const shouldThrowOnInsufficientBalanceOrAllowance = false; const params = signedOrderUtils.getOrderAddressesAndValues(signedOrder); const orderHash = await this._exchange.getOrderHash.callAsync(params.orderAddresses, params.orderValues); return orderHash; diff --git a/packages/contracts/util/formatters.ts b/packages/contracts/util/formatters.ts index 8e0dfb09e..e3080af15 100644 --- a/packages/contracts/util/formatters.ts +++ b/packages/contracts/util/formatters.ts @@ -2,19 +2,17 @@ import { SignedOrder } from '0x.js'; import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import { BatchCancelOrders, BatchFillOrders, FillOrdersUpTo } from './types'; +import { BatchCancelOrders, BatchFillOrders, MarketFillOrders } from './types'; export const formatters = { createBatchFill( signedOrders: SignedOrder[], - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - fillTakerTokenAmounts: BigNumber[] = [], + takerTokenFillAmounts: BigNumber[] = [], ) { const batchFill: BatchFillOrders = { orderAddresses: [], orderValues: [], - fillTakerTokenAmounts, - shouldThrowOnInsufficientBalanceOrAllowance, + takerTokenFillAmounts, v: [], r: [], s: [], @@ -38,35 +36,33 @@ export const formatters = { batchFill.v.push(signedOrder.ecSignature.v); batchFill.r.push(signedOrder.ecSignature.r); batchFill.s.push(signedOrder.ecSignature.s); - if (fillTakerTokenAmounts.length < signedOrders.length) { - batchFill.fillTakerTokenAmounts.push(signedOrder.takerTokenAmount); + if (takerTokenFillAmounts.length < signedOrders.length) { + batchFill.takerTokenFillAmounts.push(signedOrder.takerTokenAmount); } }); return batchFill; }, - createFillUpTo( + createMarketFillOrders( signedOrders: SignedOrder[], - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - fillTakerTokenAmount: BigNumber, + takerTokenFillAmount: BigNumber, ) { - const fillUpTo: FillOrdersUpTo = { + const marketFillOrders: MarketFillOrders = { orderAddresses: [], orderValues: [], - fillTakerTokenAmount, - shouldThrowOnInsufficientBalanceOrAllowance, + takerTokenFillAmount, v: [], r: [], s: [], }; signedOrders.forEach(signedOrder => { - fillUpTo.orderAddresses.push([ + marketFillOrders.orderAddresses.push([ signedOrder.maker, signedOrder.taker, signedOrder.makerTokenAddress, signedOrder.takerTokenAddress, signedOrder.feeRecipient, ]); - fillUpTo.orderValues.push([ + marketFillOrders.orderValues.push([ signedOrder.makerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerFee, @@ -74,11 +70,11 @@ export const formatters = { signedOrder.expirationUnixTimestampSec, signedOrder.salt, ]); - fillUpTo.v.push(signedOrder.ecSignature.v); - fillUpTo.r.push(signedOrder.ecSignature.r); - fillUpTo.s.push(signedOrder.ecSignature.s); + marketFillOrders.v.push(signedOrder.ecSignature.v); + marketFillOrders.r.push(signedOrder.ecSignature.r); + marketFillOrders.s.push(signedOrder.ecSignature.s); }); - return fillUpTo; + return marketFillOrders; }, createBatchCancel(signedOrders: SignedOrder[], cancelTakerTokenAmounts: BigNumber[] = []) { const batchCancel: BatchCancelOrders = { diff --git a/packages/contracts/util/order.ts b/packages/contracts/util/order.ts new file mode 100644 index 000000000..b42149d38 --- /dev/null +++ b/packages/contracts/util/order.ts @@ -0,0 +1,105 @@ +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 { OrderParams } from './types'; + +export class Order { + public params: OrderParams; + private _web3Wrapper: Web3Wrapper; + constructor(web3Wrapper: Web3Wrapper, params: OrderParams) { + this.params = params; + this._web3Wrapper = web3Wrapper; + } + public isValidSignature() { + const { v, r, s } = this.params; + if (_.isUndefined(v) || _.isUndefined(r) || _.isUndefined(s)) { + throw new Error('Cannot call isValidSignature on unsigned order'); + } + const orderHash = this._getOrderHash(); + const msgHash = ethUtil.hashPersonalMessage(ethUtil.toBuffer(orderHash)); + try { + const pubKey = ethUtil.ecrecover(msgHash, v, ethUtil.toBuffer(r), ethUtil.toBuffer(s)); + const recoveredAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); + return recoveredAddress === this.params.maker; + } catch (err) { + return false; + } + } + public async signAsync() { + const orderHash = this._getOrderHash(); + const signature = await this._web3Wrapper.signTransactionAsync(this.params.maker, orderHash); + const { v, r, s } = ethUtil.fromRpcSig(signature); + this.params = _.assign(this.params, { + orderHashHex: orderHash, + v, + r: ethUtil.bufferToHex(r), + s: ethUtil.bufferToHex(s), + }); + } + public createFill(takerTokenFillAmount?: BigNumber) { + const fill = { + orderAddresses: [ + this.params.maker, + this.params.taker, + this.params.makerToken, + this.params.takerToken, + this.params.feeRecipient, + ], + orderValues: [ + this.params.makerTokenAmount, + this.params.takerTokenAmount, + this.params.makerFee, + this.params.takerFee, + this.params.expirationTimestampInSec, + this.params.salt, + ], + takerTokenFillAmount: takerTokenFillAmount || this.params.takerTokenAmount, + v: this.params.v, + r: this.params.r, + s: this.params.s, + }; + return fill; + } + public createCancel(takerTokenCancelAmount?: BigNumber) { + const cancel = { + orderAddresses: [ + this.params.maker, + this.params.taker, + this.params.makerToken, + this.params.takerToken, + this.params.feeRecipient, + ], + orderValues: [ + this.params.makerTokenAmount, + this.params.takerTokenAmount, + this.params.makerFee, + this.params.takerFee, + this.params.expirationTimestampInSec, + this.params.salt, + ], + takerTokenCancelAmount: takerTokenCancelAmount || this.params.takerTokenAmount, + }; + return cancel; + } + private _getOrderHash(): string { + const orderHash = crypto.solSHA3([ + this.params.exchangeContractAddress, + this.params.maker, + this.params.taker, + this.params.makerToken, + this.params.takerToken, + this.params.feeRecipient, + this.params.makerTokenAmount, + this.params.takerTokenAmount, + this.params.makerFee, + this.params.takerFee, + this.params.expirationTimestampInSec, + this.params.salt, + ]); + const orderHashHex = ethUtil.bufferToHex(orderHash); + return orderHashHex; + } +} diff --git a/packages/contracts/util/signed_order_utils.ts b/packages/contracts/util/signed_order_utils.ts index fc2f800cd..3e5d2f226 100644 --- a/packages/contracts/util/signed_order_utils.ts +++ b/packages/contracts/util/signed_order_utils.ts @@ -9,21 +9,19 @@ import { crypto } from './crypto'; export const signedOrderUtils = { createFill: ( signedOrder: SignedOrder, - shouldThrowOnInsufficientBalanceOrAllowance?: boolean, - fillTakerTokenAmount?: BigNumber, + takerTokenFillAmount?: BigNumber, ) => { const fill = { ...signedOrderUtils.getOrderAddressesAndValues(signedOrder), - fillTakerTokenAmount: fillTakerTokenAmount || signedOrder.takerTokenAmount, - shouldThrowOnInsufficientBalanceOrAllowance: !!shouldThrowOnInsufficientBalanceOrAllowance, + takerTokenFillAmount: takerTokenFillAmount || signedOrder.takerTokenAmount, ...signedOrder.ecSignature, }; return fill; }, - createCancel(signedOrder: SignedOrder, cancelTakerTokenAmount?: BigNumber) { + createCancel(signedOrder: SignedOrder, takerTokenCancelAmount?: BigNumber) { const cancel = { ...signedOrderUtils.getOrderAddressesAndValues(signedOrder), - cancelTakerTokenAmount: cancelTakerTokenAmount || signedOrder.takerTokenAmount, + takerTokenCancelAmount: takerTokenCancelAmount || signedOrder.takerTokenAmount, }; return cancel; }, diff --git a/packages/contracts/util/types.ts b/packages/contracts/util/types.ts index 321084c42..a06e99532 100644 --- a/packages/contracts/util/types.ts +++ b/packages/contracts/util/types.ts @@ -14,18 +14,16 @@ export interface SubmissionContractEventArgs { export interface BatchFillOrders { orderAddresses: string[][]; orderValues: BigNumber[][]; - fillTakerTokenAmounts: BigNumber[]; - shouldThrowOnInsufficientBalanceOrAllowance: boolean; + takerTokenFillAmounts: BigNumber[]; v: number[]; r: string[]; s: string[]; } -export interface FillOrdersUpTo { +export interface MarketFillOrders { orderAddresses: string[][]; orderValues: BigNumber[][]; - fillTakerTokenAmount: BigNumber; - shouldThrowOnInsufficientBalanceOrAllowance: boolean; + takerTokenFillAmount: BigNumber; v: number[]; r: string[]; s: string[]; |