diff options
| author | Fabio Berger <me@fabioberger.com> | 2018-08-19 03:23:16 +0800 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-08-19 03:23:16 +0800 | 
| commit | fae58ca69597a69ef8b27e3398fb7c8a60392eef (patch) | |
| tree | 5c686d61e9cf48cef54e04dd7cde1d74a1becef9 /packages/contract-wrappers | |
| parent | ddf85112d7e4eb1581e0d82ce6eedad429641106 (diff) | |
| parent | 1c68057999ad9cb8be5018bffeeb6c1e45e645ad (diff) | |
| download | dexon-sol-tools-fae58ca69597a69ef8b27e3398fb7c8a60392eef.tar.gz dexon-sol-tools-fae58ca69597a69ef8b27e3398fb7c8a60392eef.tar.zst dexon-sol-tools-fae58ca69597a69ef8b27e3398fb7c8a60392eef.zip  | |
Merge pull request #975 from 0xProject/feature/contract-wrappers/executeTransaction
[Contract-wrappers] Exchange execute transaction encoder
Diffstat (limited to 'packages/contract-wrappers')
4 files changed, 524 insertions, 0 deletions
diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index fdf779338..d50043b0d 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,5 +1,14 @@  [      { +        "version": "1.0.1-rc.4", +        "changes": [ +            { +                "pr": 975, +                "note": "Added Transaction Encoder for use with 0x Exchange executeTransaction" +            } +        ] +    }, +    {          "version": "1.0.1-rc.3",          "changes": [              { diff --git a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts index 48bd00f90..5a4b40547 100644 --- a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts @@ -21,6 +21,7 @@ import {  } from '../types';  import { assert } from '../utils/assert';  import { decorators } from '../utils/decorators'; +import { TransactionEncoder } from '../utils/transaction_encoder';  import { ContractWrapper } from './contract_wrapper';  import { ExchangeContract, ExchangeEventArgs, ExchangeEvents } from './generated/exchange'; @@ -1097,6 +1098,16 @@ export class ExchangeWrapper extends ContractWrapper {          const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxTokenAddress);          return zrxAssetData;      } +    /** +     * Returns a Transaction Encoder. Transaction messages exist for the purpose of calling methods on the Exchange contract +     * in the context of another address. +     * @return TransactionEncoder +     */ +    public async transactionEncoderAsync(): Promise<TransactionEncoder> { +        const exchangeInstance = await this._getExchangeContractAsync(); +        const encoder = new TransactionEncoder(exchangeInstance); +        return encoder; +    }      // tslint:disable:no-unused-variable      private _invalidateContractInstances(): void {          this.unsubscribeAll(); diff --git a/packages/contract-wrappers/src/utils/transaction_encoder.ts b/packages/contract-wrappers/src/utils/transaction_encoder.ts new file mode 100644 index 000000000..5c2a94b74 --- /dev/null +++ b/packages/contract-wrappers/src/utils/transaction_encoder.ts @@ -0,0 +1,293 @@ +import { schemas } from '@0xproject/json-schemas'; +import { EIP712Schema, EIP712Types, EIP712Utils } from '@0xproject/order-utils'; +import { Order, SignedOrder } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import _ = require('lodash'); + +import { ExchangeContract } from '../contract_wrappers/generated/exchange'; + +import { assert } from './assert'; + +const EIP712_ZEROEX_TRANSACTION_SCHEMA: EIP712Schema = { +    name: 'ZeroExTransaction', +    parameters: [ +        { name: 'salt', type: EIP712Types.Uint256 }, +        { name: 'signerAddress', type: EIP712Types.Address }, +        { name: 'data', type: EIP712Types.Bytes }, +    ], +}; + +/** + * Transaction Encoder. Transaction messages exist for the purpose of calling methods on the Exchange contract + * in the context of another address. For example, UserA can encode and sign a fillOrder transaction and UserB + * can submit this to the blockchain. The Exchange context executes as if UserA had directly submitted this transaction. + */ +export class TransactionEncoder { +    private _exchangeInstance: ExchangeContract; +    constructor(exchangeInstance: ExchangeContract) { +        this._exchangeInstance = exchangeInstance; +    } +    /** +     * Encodes the transaction data for use with the Exchange contract. +     * @param data The ABI Encoded 0x Exchange method. I.e fillOrder +     * @param salt A random value to provide uniqueness and prevent replay attacks. +     * @param signerAddress The address which will sign this transaction. +     * @return An unsigned hex encoded transaction for use in 0x Exchange executeTransaction. +     */ +    public getTransactionHex(data: string, salt: BigNumber, signerAddress: string): string { +        const exchangeAddress = this._getExchangeContract().address; +        const executeTransactionData = { +            salt, +            signerAddress, +            data, +        }; +        const executeTransactionHashBuff = EIP712Utils.structHash( +            EIP712_ZEROEX_TRANSACTION_SCHEMA, +            executeTransactionData, +        ); +        const eip721MessageBuffer = EIP712Utils.createEIP712Message(executeTransactionHashBuff, exchangeAddress); +        const messageHex = `0x${eip721MessageBuffer.toString('hex')}`; +        return messageHex; +    } +    /** +     * Encodes a fillOrder transaction. +     * @param  signedOrder           An object that conforms to the SignedOrder interface. +     * @param  takerAssetFillAmount  The amount of the order (in taker asset baseUnits) that you wish to fill. +     * @return Hex encoded abi of the function call. +     */ +    public fillOrderTx(signedOrder: SignedOrder, takerAssetFillAmount: BigNumber): string { +        assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); +        assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); +        const abiEncodedData = this._getExchangeContract().fillOrder.getABIEncodedTransactionData( +            signedOrder, +            takerAssetFillAmount, +            signedOrder.signature, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a fillOrderNoThrow transaction. +     * @param  signedOrder           An object that conforms to the SignedOrder interface. +     * @param  takerAssetFillAmount  The amount of the order (in taker asset baseUnits) that you wish to fill. +     * @return Hex encoded abi of the function call. +     */ +    public fillOrderNoThrowTx(signedOrder: SignedOrder, takerAssetFillAmount: BigNumber): string { +        assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); +        assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); +        const abiEncodedData = this._getExchangeContract().fillOrderNoThrow.getABIEncodedTransactionData( +            signedOrder, +            takerAssetFillAmount, +            signedOrder.signature, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a fillOrKillOrder transaction. +     * @param  signedOrder           An object that conforms to the SignedOrder interface. +     * @param  takerAssetFillAmount  The amount of the order (in taker asset baseUnits) that you wish to fill. +     * @return Hex encoded abi of the function call. +     */ +    public fillOrKillOrderTx(signedOrder: SignedOrder, takerAssetFillAmount: BigNumber): string { +        assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); +        assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); +        const abiEncodedData = this._getExchangeContract().fillOrKillOrder.getABIEncodedTransactionData( +            signedOrder, +            takerAssetFillAmount, +            signedOrder.signature, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a batchFillOrders transaction. +     * @param   signedOrders          An array of signed orders to fill. +     * @param   takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. +     * @return Hex encoded abi of the function call. +     */ +    public batchFillOrdersTx(signedOrders: SignedOrder[], takerAssetFillAmounts: BigNumber[]): string { +        assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); +        _.forEach(takerAssetFillAmounts, takerAssetFillAmount => +            assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount), +        ); +        const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); +        const abiEncodedData = this._getExchangeContract().batchFillOrders.getABIEncodedTransactionData( +            signedOrders, +            takerAssetFillAmounts, +            signatures, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a batchFillOrKillOrders transaction. +     * @param   signedOrders          An array of signed orders to fill. +     * @param   takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. +     * @return Hex encoded abi of the function call. +     */ +    public batchFillOrKillOrdersTx(signedOrders: SignedOrder[], takerAssetFillAmounts: BigNumber[]): string { +        assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); +        _.forEach(takerAssetFillAmounts, takerAssetFillAmount => +            assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount), +        ); +        const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); +        const abiEncodedData = this._getExchangeContract().batchFillOrKillOrders.getABIEncodedTransactionData( +            signedOrders, +            takerAssetFillAmounts, +            signatures, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a batchFillOrdersNoThrow transaction. +     * @param   signedOrders          An array of signed orders to fill. +     * @param   takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. +     * @return Hex encoded abi of the function call. +     */ +    public batchFillOrdersNoThrowTx(signedOrders: SignedOrder[], takerAssetFillAmounts: BigNumber[]): string { +        assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); +        _.forEach(takerAssetFillAmounts, takerAssetFillAmount => +            assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount), +        ); +        const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); +        const abiEncodedData = this._getExchangeContract().batchFillOrdersNoThrow.getABIEncodedTransactionData( +            signedOrders, +            takerAssetFillAmounts, +            signatures, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a batchCancelOrders transaction. +     * @param   signedOrders An array of orders to cancel. +     * @return Hex encoded abi of the function call. +     */ +    public batchCancelOrdersTx(signedOrders: SignedOrder[]): string { +        assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); +        const abiEncodedData = this._getExchangeContract().batchCancelOrders.getABIEncodedTransactionData(signedOrders); +        return abiEncodedData; +    } +    /** +     * Encodes a cancelOrdersUpTo transaction. +     * @param  targetOrderEpoch Target order epoch. +     * @return Hex encoded abi of the function call. +     */ +    public cancelOrdersUpToTx(targetOrderEpoch: BigNumber): string { +        assert.isBigNumber('targetOrderEpoch', targetOrderEpoch); +        const abiEncodedData = this._getExchangeContract().cancelOrdersUpTo.getABIEncodedTransactionData( +            targetOrderEpoch, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a cancelOrder transaction. +     * @param  order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel. +     * @return Hex encoded abi of the function call. +     */ +    public cancelOrderTx(order: Order | SignedOrder): string { +        assert.doesConformToSchema('order', order, schemas.orderSchema); +        const abiEncodedData = this._getExchangeContract().cancelOrder.getABIEncodedTransactionData(order); +        return abiEncodedData; +    } +    /** +     * Encodes a marketSellOrders transaction. +     * @param   signedOrders         An array of signed orders to fill. +     * @param   takerAssetFillAmount Taker asset fill amount. +     * @return Hex encoded abi of the function call. +     */ +    public marketSellOrdersTx(signedOrders: SignedOrder[], takerAssetFillAmount: BigNumber): string { +        assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); +        assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); +        const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); +        const abiEncodedData = this._getExchangeContract().marketSellOrders.getABIEncodedTransactionData( +            signedOrders, +            takerAssetFillAmount, +            signatures, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a marketSellOrdersNoThrow transaction. +     * @param   signedOrders         An array of signed orders to fill. +     * @param   takerAssetFillAmount Taker asset fill amount. +     * @return Hex encoded abi of the function call. +     */ +    public marketSellOrdersNoThrowTx(signedOrders: SignedOrder[], takerAssetFillAmount: BigNumber): string { +        assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); +        assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); +        const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); +        const abiEncodedData = this._getExchangeContract().marketSellOrdersNoThrow.getABIEncodedTransactionData( +            signedOrders, +            takerAssetFillAmount, +            signatures, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a maketBuyOrders transaction. +     * @param   signedOrders         An array of signed orders to fill. +     * @param   makerAssetFillAmount Maker asset fill amount. +     * @return Hex encoded abi of the function call. +     */ +    public marketBuyOrdersTx(signedOrders: SignedOrder[], makerAssetFillAmount: BigNumber): string { +        assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); +        assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount); +        const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); +        const abiEncodedData = this._getExchangeContract().marketBuyOrders.getABIEncodedTransactionData( +            signedOrders, +            makerAssetFillAmount, +            signatures, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a maketBuyOrdersNoThrow transaction. +     * @param   signedOrders         An array of signed orders to fill. +     * @param   makerAssetFillAmount Maker asset fill amount. +     * @return Hex encoded abi of the function call. +     */ +    public marketBuyOrdersNoThrowTx(signedOrders: SignedOrder[], makerAssetFillAmount: BigNumber): string { +        assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); +        assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount); +        const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); +        const abiEncodedData = this._getExchangeContract().marketBuyOrdersNoThrow.getABIEncodedTransactionData( +            signedOrders, +            makerAssetFillAmount, +            signatures, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a preSign transaction. +     * @param hash          Hash to pre-sign +     * @param signerAddress Address that should have signed the given hash. +     * @param signature     Proof that the hash has been signed by signer. +     * @return Hex encoded abi of the function call. +     */ +    public preSignTx(hash: string, signerAddress: string, signature: string): string { +        assert.isHexString('hash', hash); +        assert.isETHAddressHex('signerAddress', signerAddress); +        assert.isHexString('signature', signature); +        const abiEncodedData = this._getExchangeContract().preSign.getABIEncodedTransactionData( +            hash, +            signerAddress, +            signature, +        ); +        return abiEncodedData; +    } +    /** +     * Encodes a setSignatureValidatorApproval transaction. +     * @param   validatorAddress        Validator contract address. +     * @param   isApproved              Boolean value to set approval to. +     * @return Hex encoded abi of the function call. +     */ +    public setSignatureValidatorApprovalTx(validatorAddress: string, isApproved: boolean): string { +        assert.isETHAddressHex('validatorAddress', validatorAddress); +        assert.isBoolean('isApproved', isApproved); +        const abiEncodedData = this._getExchangeContract().setSignatureValidatorApproval.getABIEncodedTransactionData( +            validatorAddress, +            isApproved, +        ); +        return abiEncodedData; +    } +    private _getExchangeContract(): ExchangeContract { +        return this._exchangeInstance; +    } +} diff --git a/packages/contract-wrappers/test/transaction_encoder_test.ts b/packages/contract-wrappers/test/transaction_encoder_test.ts new file mode 100644 index 000000000..10222dbc1 --- /dev/null +++ b/packages/contract-wrappers/test/transaction_encoder_test.ts @@ -0,0 +1,211 @@ +import { BlockchainLifecycle } from '@0xproject/dev-utils'; +import { FillScenarios } from '@0xproject/fill-scenarios'; +import { assetDataUtils, ecSignOrderHashAsync, generatePseudoRandomSalt, orderHashUtils } from '@0xproject/order-utils'; +import { SignedOrder, SignerType } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; +import 'mocha'; + +import { ContractWrappers } from '../src'; +import { TransactionEncoder } from '../src/utils/transaction_encoder'; + +import { constants } from './utils/constants'; +import { tokenUtils } from './utils/token_utils'; +import { provider, web3Wrapper } from './utils/web3_wrapper'; + +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); + +describe('TransactionEncoder', () => { +    let contractWrappers: ContractWrappers; +    let userAddresses: string[]; +    let fillScenarios: FillScenarios; +    let exchangeContractAddress: string; +    let makerTokenAddress: string; +    let takerTokenAddress: string; +    let coinbase: string; +    let makerAddress: string; +    let senderAddress: string; +    let takerAddress: string; +    let makerAssetData: string; +    let takerAssetData: string; +    let txHash: string; +    const fillableAmount = new BigNumber(5); +    const takerTokenFillAmount = new BigNumber(5); +    let signedOrder: SignedOrder; +    const config = { +        networkId: constants.TESTRPC_NETWORK_ID, +        blockPollingIntervalMs: 0, +    }; +    before(async () => { +        await blockchainLifecycle.startAsync(); +        contractWrappers = new ContractWrappers(provider, config); +        exchangeContractAddress = contractWrappers.exchange.getContractAddress(); +        userAddresses = await web3Wrapper.getAvailableAddressesAsync(); +        const zrxTokenAddress = tokenUtils.getProtocolTokenAddress(); +        fillScenarios = new FillScenarios( +            provider, +            userAddresses, +            zrxTokenAddress, +            exchangeContractAddress, +            contractWrappers.erc20Proxy.getContractAddress(), +            contractWrappers.erc721Proxy.getContractAddress(), +        ); +        [coinbase, makerAddress, takerAddress, senderAddress] = userAddresses; +        [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); +        [makerAssetData, takerAssetData] = [ +            assetDataUtils.encodeERC20AssetData(makerTokenAddress), +            assetDataUtils.encodeERC20AssetData(takerTokenAddress), +        ]; +        signedOrder = await fillScenarios.createFillableSignedOrderAsync( +            makerAssetData, +            takerAssetData, +            makerAddress, +            takerAddress, +            fillableAmount, +        ); +    }); +    after(async () => { +        await blockchainLifecycle.revertAsync(); +    }); +    beforeEach(async () => { +        await blockchainLifecycle.startAsync(); +    }); +    afterEach(async () => { +        await blockchainLifecycle.revertAsync(); +    }); +    describe('encode and executeTransaction', () => { +        const executeTransactionOrThrowAsync = async ( +            encoder: TransactionEncoder, +            data: string, +            signerAddress: string = takerAddress, +        ): Promise<void> => { +            const salt = generatePseudoRandomSalt(); +            const encodedTransaction = encoder.getTransactionHex(data, salt, signerAddress); +            const signature = await ecSignOrderHashAsync( +                provider, +                encodedTransaction, +                signerAddress, +                SignerType.Default, +            ); +            txHash = await contractWrappers.exchange.executeTransactionAsync( +                salt, +                signerAddress, +                data, +                signature, +                senderAddress, +            ); +            await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); +        }; +        describe('#fillOrderTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.fillOrderTx(signedOrder, takerTokenFillAmount); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#fillOrderNoThrowTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.fillOrderNoThrowTx(signedOrder, takerTokenFillAmount); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#fillOrKillOrderTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.fillOrKillOrderTx(signedOrder, takerTokenFillAmount); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#marketSellOrdersTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.marketSellOrdersTx([signedOrder], takerTokenFillAmount); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#marketSellOrdersNoThrowTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.marketSellOrdersNoThrowTx([signedOrder], takerTokenFillAmount); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#marketBuyOrdersTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.marketBuyOrdersTx([signedOrder], fillableAmount); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#marketBuyOrdersNoThrowTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.marketBuyOrdersNoThrowTx([signedOrder], fillableAmount); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#preSignTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const orderHash = orderHashUtils.getOrderHashHex(signedOrder); +                const signature = signedOrder.signature; +                const data = encoder.preSignTx(orderHash, makerAddress, signature); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#setSignatureValidatorApprovalTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const isApproved = true; +                const data = encoder.setSignatureValidatorApprovalTx(senderAddress, isApproved); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#batchFillOrdersTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.batchFillOrdersTx([signedOrder], [takerTokenFillAmount]); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#batchFillOrKillOrdersTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.batchFillOrKillOrdersTx([signedOrder], [takerTokenFillAmount]); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#batchFillOrdersNoThrowTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.batchFillOrdersNoThrowTx([signedOrder], [takerTokenFillAmount]); +                await executeTransactionOrThrowAsync(encoder, data); +            }); +        }); +        describe('#batchCancelOrdersTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.batchCancelOrdersTx([signedOrder]); +                const signerAddress = makerAddress; +                await executeTransactionOrThrowAsync(encoder, data, signerAddress); +            }); +        }); +        describe('#cancelOrderTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const data = encoder.cancelOrderTx(signedOrder); +                const signerAddress = makerAddress; +                await executeTransactionOrThrowAsync(encoder, data, signerAddress); +            }); +        }); +        describe('#cancelOrdersUpToTx', () => { +            it('should successfully execute the transaction', async () => { +                const encoder = await contractWrappers.exchange.transactionEncoderAsync(); +                const targetEpoch = signedOrder.salt; +                const data = encoder.cancelOrdersUpToTx(targetEpoch); +                const signerAddress = makerAddress; +                await executeTransactionOrThrowAsync(encoder, data, signerAddress); +            }); +        }); +    }); +});  | 
