import { ExchangeContract } from '@0x/contracts-exchange'; import { FillResults, formatters, LogDecoder, OrderInfo, orderUtils, TransactionFactory, Web3ProviderEngine, } from '@0x/contracts-test-utils'; import { SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import { BalanceThresholdFilterContract } from './wrappers'; import { artifacts } from './artifacts'; export class BalanceThresholdWrapper { private readonly _balanceThresholdFilter: BalanceThresholdFilterContract; private readonly _signerTransactionFactory: TransactionFactory; private readonly _exchange: ExchangeContract; private readonly _web3Wrapper: Web3Wrapper; private readonly _logDecoder: LogDecoder; constructor( balanceThresholdFilter: BalanceThresholdFilterContract, exchangeContract: ExchangeContract, signerTransactionFactory: TransactionFactory, provider: Web3ProviderEngine, ) { this._balanceThresholdFilter = balanceThresholdFilter; this._exchange = exchangeContract; this._signerTransactionFactory = signerTransactionFactory; this._web3Wrapper = new Web3Wrapper(provider); this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); } public async fillOrderAsync( signedOrder: SignedOrder, from: string, opts: { takerAssetFillAmount?: BigNumber } = {}, ): Promise { const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); const data = this._exchange .fillOrder(params.order, params.takerAssetFillAmount, params.signature) .getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from); return txReceipt; } public async fillOrKillOrderAsync( signedOrder: SignedOrder, from: string, opts: { takerAssetFillAmount?: BigNumber } = {}, ): Promise { const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); const data = this._exchange .fillOrKillOrder(params.order, params.takerAssetFillAmount, params.signature) .getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from); return txReceipt; } public async fillOrderNoThrowAsync( signedOrder: SignedOrder, from: string, opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {}, ): Promise { const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); const data = this._exchange .fillOrderNoThrow(params.order, params.takerAssetFillAmount, params.signature) .getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from, opts.gas); return txReceipt; } public async batchFillOrdersAsync( orders: SignedOrder[], from: string, opts: { takerAssetFillAmounts?: BigNumber[] } = {}, ): Promise { const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); const data = this._exchange .batchFillOrders(params.orders, params.takerAssetFillAmounts, params.signatures) .getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from); return txReceipt; } public async batchFillOrKillOrdersAsync( orders: SignedOrder[], from: string, opts: { takerAssetFillAmounts?: BigNumber[] } = {}, ): Promise { const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); const data = this._exchange .batchFillOrKillOrders(params.orders, params.takerAssetFillAmounts, params.signatures) .getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from); return txReceipt; } public async batchFillOrdersNoThrowAsync( orders: SignedOrder[], from: string, opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {}, ): Promise { const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts); const data = this._exchange .batchFillOrKillOrders(params.orders, params.takerAssetFillAmounts, params.signatures) .getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from, opts.gas); return txReceipt; } public async marketSellOrdersAsync( orders: SignedOrder[], from: string, opts: { takerAssetFillAmount: BigNumber }, ): Promise { const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount); const data = this._exchange .marketSellOrders(params.orders, params.takerAssetFillAmount, params.signatures) .getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from); return txReceipt; } public async marketSellOrdersNoThrowAsync( orders: SignedOrder[], from: string, opts: { takerAssetFillAmount: BigNumber; gas?: number }, ): Promise { const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount); const data = this._exchange .marketSellOrdersNoThrow(params.orders, params.takerAssetFillAmount, params.signatures) .getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from, opts.gas); return txReceipt; } public async marketBuyOrdersAsync( orders: SignedOrder[], from: string, opts: { makerAssetFillAmount: BigNumber }, ): Promise { const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount); const data = this._exchange .marketBuyOrders(params.orders, params.makerAssetFillAmount, params.signatures) .getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from); return txReceipt; } public async marketBuyOrdersNoThrowAsync( orders: SignedOrder[], from: string, opts: { makerAssetFillAmount: BigNumber; gas?: number }, ): Promise { const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount); const data = this._exchange .marketBuyOrdersNoThrow(params.orders, params.makerAssetFillAmount, params.signatures) .getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from, opts.gas); return txReceipt; } public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise { const params = orderUtils.createCancel(signedOrder); const data = this._exchange.cancelOrder(params.order).getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from); return txReceipt; } public async batchCancelOrdersAsync( orders: SignedOrder[], from: string, ): Promise { const params = formatters.createBatchCancel(orders); const data = this._exchange.batchCancelOrders(params.orders).getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from); return txReceipt; } public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise { const data = this._exchange.cancelOrdersUpTo(salt).getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from); return txReceipt; } public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise { const filledAmount = await this._exchange.filled(orderHashHex).callAsync(); return filledAmount; } public async isCancelledAsync(orderHashHex: string): Promise { const isCancelled = await this._exchange.cancelled(orderHashHex).callAsync(); return isCancelled; } public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise { const orderEpoch = await this._exchange.orderEpoch(makerAddress, senderAddress).callAsync(); return orderEpoch; } public async getOrderInfoAsync(signedOrder: SignedOrder): Promise { const orderInfo = await this._exchange.getOrderInfo(signedOrder).callAsync(); return orderInfo; } public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise { const ordersInfo = (await this._exchange.getOrdersInfo(signedOrders)).callAsync() as OrderInfo[]; return ordersInfo; } public async matchOrdersAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, from: string, ): Promise { const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight); const data = this._exchange .matchOrders(params.left, params.right, params.leftSignature, params.rightSignature) .getABIEncodedTransactionData(); const txReceipt = this._executeTransactionAsync(data, from); return txReceipt; } public async getFillOrderResultsAsync( signedOrder: SignedOrder, from: string, opts: { takerAssetFillAmount?: BigNumber } = {}, ): Promise { const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); const fillResults = await this._exchange .fillOrder(params.order, params.takerAssetFillAmount, params.signature) .callAsync({ from }); return fillResults; } public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string { const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); const data = this._exchange .fillOrder(params.order, params.takerAssetFillAmount, params.signature) .getABIEncodedTransactionData(); return data; } public getBalanceThresholdAddress(): string { return this._balanceThresholdFilter.address; } public getExchangeAddress(): string { return this._exchange.address; } private async _executeTransactionAsync( abiEncodedExchangeTxData: string, from: string, gas?: number, ): Promise { const signedExchangeTx = this._signerTransactionFactory.newSignedTransaction(abiEncodedExchangeTxData); const txOpts = gas === undefined ? { from } : { from, gas }; const txHash = await this._balanceThresholdFilter .executeTransaction( signedExchangeTx.salt, signedExchangeTx.signerAddress, signedExchangeTx.data, signedExchangeTx.signature, txOpts, ) .sendTransactionAsync(); const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); return txReceipt; } }