From 9b922f746bfc1db9ca90f3222b29243ef077481a Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Mon, 30 Sep 2019 19:22:18 -0700 Subject: [PATCH] Update coordinator tests --- .../contracts/src/MixinSignatureValidator.sol | 2 +- contracts/coordinator/package.json | 2 +- contracts/coordinator/src/artifacts.ts | 24 + contracts/coordinator/src/wrappers.ts | 12 + contracts/coordinator/test/coordinator.ts | 514 ++++++++---------- .../coordinator/test/coordinator_registry.ts | 27 +- contracts/coordinator/test/libs.ts | 49 +- contracts/coordinator/test/mixins.ts | 300 +++++----- .../utils/coordinator_registry_wrapper.ts | 3 +- contracts/coordinator/tsconfig.json | 17 +- packages/order-utils/src/constants.ts | 2 +- .../src/coordinator_revert_errors.ts | 8 +- packages/order-utils/src/eip712_utils.ts | 2 +- packages/order-utils/src/index.ts | 1 + 14 files changed, 455 insertions(+), 508 deletions(-) diff --git a/contracts/coordinator/contracts/src/MixinSignatureValidator.sol b/contracts/coordinator/contracts/src/MixinSignatureValidator.sol index 0f940d135e..8a3e79dac2 100644 --- a/contracts/coordinator/contracts/src/MixinSignatureValidator.sol +++ b/contracts/coordinator/contracts/src/MixinSignatureValidator.sol @@ -48,7 +48,7 @@ contract MixinSignatureValidator is } // Pop last byte off of signature byte array. - uint8 signatureTypeRaw = uint8(signature.popLastByte()); + uint8 signatureTypeRaw = uint8(signature[signature.length - 1]); // Ensure signature is supported if (signatureTypeRaw >= uint8(SignatureType.NSignatureTypes)) { diff --git a/contracts/coordinator/package.json b/contracts/coordinator/package.json index 17b480ea21..16de8c364c 100644 --- a/contracts/coordinator/package.json +++ b/contracts/coordinator/package.json @@ -35,7 +35,7 @@ "compile:truffle": "truffle compile" }, "config": { - "abis": "./generated-artifacts/@(Coordinator|CoordinatorRegistry).json", + "abis": "./generated-artifacts/@(Coordinator|CoordinatorRegistry|ICoordinatorApprovalVerifier|ICoordinatorCore|ICoordinatorRegistryCore|ICoordinatorSignatureValidator|LibConstants|LibCoordinatorApproval|LibCoordinatorRichErrors|LibEIP712CoordinatorDomain|MixinCoordinatorApprovalVerifier|MixinCoordinatorCore|MixinCoordinatorRegistryCore|MixinSignatureValidator).json", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." }, "repository": { diff --git a/contracts/coordinator/src/artifacts.ts b/contracts/coordinator/src/artifacts.ts index 8276964486..9722198ad8 100644 --- a/contracts/coordinator/src/artifacts.ts +++ b/contracts/coordinator/src/artifacts.ts @@ -7,7 +7,31 @@ import { ContractArtifact } from 'ethereum-types'; import * as Coordinator from '../generated-artifacts/Coordinator.json'; import * as CoordinatorRegistry from '../generated-artifacts/CoordinatorRegistry.json'; +import * as ICoordinatorApprovalVerifier from '../generated-artifacts/ICoordinatorApprovalVerifier.json'; +import * as ICoordinatorCore from '../generated-artifacts/ICoordinatorCore.json'; +import * as ICoordinatorRegistryCore from '../generated-artifacts/ICoordinatorRegistryCore.json'; +import * as ICoordinatorSignatureValidator from '../generated-artifacts/ICoordinatorSignatureValidator.json'; +import * as LibConstants from '../generated-artifacts/LibConstants.json'; +import * as LibCoordinatorApproval from '../generated-artifacts/LibCoordinatorApproval.json'; +import * as LibCoordinatorRichErrors from '../generated-artifacts/LibCoordinatorRichErrors.json'; +import * as LibEIP712CoordinatorDomain from '../generated-artifacts/LibEIP712CoordinatorDomain.json'; +import * as MixinCoordinatorApprovalVerifier from '../generated-artifacts/MixinCoordinatorApprovalVerifier.json'; +import * as MixinCoordinatorCore from '../generated-artifacts/MixinCoordinatorCore.json'; +import * as MixinCoordinatorRegistryCore from '../generated-artifacts/MixinCoordinatorRegistryCore.json'; +import * as MixinSignatureValidator from '../generated-artifacts/MixinSignatureValidator.json'; export const artifacts = { Coordinator: Coordinator as ContractArtifact, + MixinCoordinatorApprovalVerifier: MixinCoordinatorApprovalVerifier as ContractArtifact, + MixinCoordinatorCore: MixinCoordinatorCore as ContractArtifact, + MixinSignatureValidator: MixinSignatureValidator as ContractArtifact, + ICoordinatorApprovalVerifier: ICoordinatorApprovalVerifier as ContractArtifact, + ICoordinatorCore: ICoordinatorCore as ContractArtifact, + ICoordinatorSignatureValidator: ICoordinatorSignatureValidator as ContractArtifact, + LibConstants: LibConstants as ContractArtifact, + LibCoordinatorApproval: LibCoordinatorApproval as ContractArtifact, + LibCoordinatorRichErrors: LibCoordinatorRichErrors as ContractArtifact, + LibEIP712CoordinatorDomain: LibEIP712CoordinatorDomain as ContractArtifact, CoordinatorRegistry: CoordinatorRegistry as ContractArtifact, + MixinCoordinatorRegistryCore: MixinCoordinatorRegistryCore as ContractArtifact, + ICoordinatorRegistryCore: ICoordinatorRegistryCore as ContractArtifact, }; diff --git a/contracts/coordinator/src/wrappers.ts b/contracts/coordinator/src/wrappers.ts index a88791dffa..1307b59821 100644 --- a/contracts/coordinator/src/wrappers.ts +++ b/contracts/coordinator/src/wrappers.ts @@ -5,3 +5,15 @@ */ export * from '../generated-wrappers/coordinator'; export * from '../generated-wrappers/coordinator_registry'; +export * from '../generated-wrappers/i_coordinator_approval_verifier'; +export * from '../generated-wrappers/i_coordinator_core'; +export * from '../generated-wrappers/i_coordinator_registry_core'; +export * from '../generated-wrappers/i_coordinator_signature_validator'; +export * from '../generated-wrappers/lib_constants'; +export * from '../generated-wrappers/lib_coordinator_approval'; +export * from '../generated-wrappers/lib_coordinator_rich_errors'; +export * from '../generated-wrappers/lib_e_i_p712_coordinator_domain'; +export * from '../generated-wrappers/mixin_coordinator_approval_verifier'; +export * from '../generated-wrappers/mixin_coordinator_core'; +export * from '../generated-wrappers/mixin_coordinator_registry_core'; +export * from '../generated-wrappers/mixin_signature_validator'; diff --git a/contracts/coordinator/test/coordinator.ts b/contracts/coordinator/test/coordinator.ts index ac3d2cd108..27e90c49f6 100644 --- a/contracts/coordinator/test/coordinator.ts +++ b/contracts/coordinator/test/coordinator.ts @@ -7,35 +7,28 @@ import { ExchangeCancelUpToEventArgs, ExchangeContract, exchangeDataEncoder, + ExchangeEvents, ExchangeFillEventArgs, ExchangeFunctionName, } from '@0x/contracts-exchange'; import { - chaiSetup, + blockchainTests, constants, - expectTransactionFailedAsync, + expect, + filterLogsToArguments, getLatestBlockTimestampAsync, OrderFactory, - provider, TransactionFactory, - txDefaults, - web3Wrapper, } from '@0x/contracts-test-utils'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { RevertReason } from '@0x/types'; -import { BigNumber, providerUtils } from '@0x/utils'; -import * as chai from 'chai'; -import { LogWithDecodedArgs } from 'ethereum-types'; +import { assetDataUtils, CoordinatorRevertErrors, orderHashUtils, transactionHashUtils } from '@0x/order-utils'; +import { SignedOrder } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import { ApprovalFactory, artifacts, CoordinatorContract } from '../src'; -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -web3Wrapper.abiDecoder.addABI(exchangeArtifacts.Exchange.compilerOutput.abi); // tslint:disable:no-unnecessary-type-assertion -describe('Coordinator tests', () => { +blockchainTests.resets('Coordinator tests', env => { let chainId: number; let makerAddress: string; let owner: string; @@ -55,18 +48,17 @@ describe('Coordinator tests', () => { let makerTransactionFactory: TransactionFactory; let approvalFactory: ApprovalFactory; - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - chainId = await providerUtils.getChainIdAsync(provider); - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts.slice(0, 4)); + // const GAS_PRICE = new BigNumber(env.txDefaults.gasPrice || constants.DEFAULT_GAS_PRICE); + // const PROTOCOL_FEE_MULTIPLIER = new BigNumber(150); + // const PROTOCOL_FEE = GAS_PRICE.times(PROTOCOL_FEE_MULTIPLIER); + const PROTOCOL_FEE = new BigNumber(0); - erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner); + before(async () => { + chainId = await env.getChainIdAsync(); + const accounts = await env.getAccountAddressesAsync(); + const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts); + + erc20Wrapper = new ERC20Wrapper(env.provider, usedAddresses, owner); erc20Proxy = await erc20Wrapper.deployProxyAsync(); const numDummyErc20ToDeploy = 3; [erc20TokenA, erc20TokenB, makerFeeToken] = await erc20Wrapper.deployDummyTokensAsync( @@ -77,26 +69,28 @@ describe('Coordinator tests', () => { exchange = await ExchangeContract.deployFrom0xArtifactAsync( exchangeArtifacts.Exchange, - provider, - txDefaults, + env.provider, + env.txDefaults, + {}, new BigNumber(chainId), ); - await web3Wrapper.awaitTransactionSuccessAsync( - await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }), + await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync( + exchange.address, + { from: owner }, constants.AWAIT_TRANSACTION_MINED_MS, ); - - await web3Wrapper.awaitTransactionSuccessAsync( - await exchange.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }), + await exchange.registerAssetProxy.awaitTransactionSuccessAsync( + erc20Proxy.address, + { from: owner }, constants.AWAIT_TRANSACTION_MINED_MS, ); coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync( artifacts.Coordinator, - provider, - txDefaults, - artifacts, + env.provider, + env.txDefaults, + { ...exchangeArtifacts, ...artifacts }, exchange.address, new BigNumber(chainId), ); @@ -106,6 +100,7 @@ describe('Coordinator tests', () => { ...constants.STATIC_ORDER_PARAMS, senderAddress: coordinatorContract.address, makerAddress, + takerAddress, feeRecipientAddress, makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address), takerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenB.address), @@ -122,12 +117,48 @@ describe('Coordinator tests', () => { takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address, chainId); approvalFactory = new ApprovalFactory(feeRecipientPrivateKey, coordinatorContract.address); }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); + + function verifyEvents( + txReceipt: TransactionReceiptWithDecodedLogs, + expectedEvents: TEventArgs[], + eventName: string, + ): void { + const logs = filterLogsToArguments(txReceipt.logs, eventName); + expect(logs.length).to.eq(expectedEvents.length); + logs.forEach((log, index) => { + expect(log).to.deep.equal(expectedEvents[index]); + }); + } + + function expectedFillEvent(order: SignedOrder): ExchangeFillEventArgs { + return { + makerAddress: order.makerAddress, + feeRecipientAddress: order.feeRecipientAddress, + makerAssetData: order.makerAssetData, + takerAssetData: order.takerAssetData, + makerFeeAssetData: order.makerFeeAssetData, + takerFeeAssetData: order.takerFeeAssetData, + takerAddress: order.takerAddress, + senderAddress: order.senderAddress, + makerAssetFilledAmount: order.makerAssetAmount, + takerAssetFilledAmount: order.takerAssetAmount, + makerFeePaid: order.makerFee, + takerFeePaid: order.takerFee, + protocolFeePaid: PROTOCOL_FEE, + orderHash: orderHashUtils.getOrderHashHex(order), + }; + } + + function expectedCancelEvent(order: SignedOrder): ExchangeCancelEventArgs { + return { + makerAddress: order.makerAddress, + feeRecipientAddress: order.feeRecipientAddress, + makerAssetData: order.makerAssetData, + takerAssetData: order.takerAssetData, + senderAddress: order.senderAddress, + orderHash: orderHashUtils.getOrderHashHex(order), + }; + } describe('single order fills', () => { for (const fnName of exchangeConstants.SINGLE_FILL_FN_NAMES) { @@ -142,83 +173,52 @@ describe('Coordinator tests', () => { takerAddress, approvalExpirationTimeSeconds, ); - const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - takerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval.signature], - { from: takerAddress }, - ), + const transactionReceipt = await coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + takerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.signature], + { from: takerAddress }, constants.AWAIT_TRANSACTION_MINED_MS, ); - const fillLogs = transactionReceipt.logs.filter( - log => (log as LogWithDecodedArgs).event === 'Fill', - ); - expect(fillLogs.length).to.eq(1); - const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs).args; - expect(fillLogArgs.makerAddress).to.eq(makerAddress); - expect(fillLogArgs.takerAddress).to.eq(takerAddress); - expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address); - expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); - expect(fillLogArgs.makerAssetData).to.eq(orders[0].makerAssetData); - expect(fillLogArgs.takerAssetData).to.eq(orders[0].takerAssetData); - expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(orders[0].makerAssetAmount); - expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(orders[0].takerAssetAmount); - expect(fillLogArgs.makerFeePaid).to.bignumber.eq(orders[0].makerFee); - expect(fillLogArgs.takerFeePaid).to.bignumber.eq(orders[0].takerFee); - expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0])); + + verifyEvents(transactionReceipt, [expectedFillEvent(orders[0])], ExchangeEvents.Fill); }); it(`${fnName} should fill the order if called by approver`, async () => { const orders = [await orderFactory.newSignedOrderAsync()]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); - const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - feeRecipientAddress, - transaction.signature, - [], - [], - { from: feeRecipientAddress }, - ), + const transactionReceipt = await coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + feeRecipientAddress, + transaction.signature, + [], + [], + { from: feeRecipientAddress }, constants.AWAIT_TRANSACTION_MINED_MS, ); - const fillLogs = transactionReceipt.logs.filter( - log => (log as LogWithDecodedArgs).event === 'Fill', - ); - expect(fillLogs.length).to.eq(1); - const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs).args; - expect(fillLogArgs.makerAddress).to.eq(makerAddress); - expect(fillLogArgs.takerAddress).to.eq(takerAddress); - expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address); - expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); - expect(fillLogArgs.makerAssetData).to.eq(orders[0].makerAssetData); - expect(fillLogArgs.takerAssetData).to.eq(orders[0].takerAssetData); - expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(orders[0].makerAssetAmount); - expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(orders[0].takerAssetAmount); - expect(fillLogArgs.makerFeePaid).to.bignumber.eq(orders[0].makerFee); - expect(fillLogArgs.takerFeePaid).to.bignumber.eq(orders[0].takerFee); - expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0])); + verifyEvents(transactionReceipt, [expectedFillEvent(orders[0])], ExchangeEvents.Fill); }); it(`${fnName} should revert with no approval signature`, async () => { const orders = [await orderFactory.newSignedOrderAsync()]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); - await expectTransactionFailedAsync( - coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - takerAddress, - transaction.signature, - [], - [], - { - from: takerAddress, - gas: constants.MAX_EXECUTE_TRANSACTION_GAS, - }, - ), - RevertReason.InvalidApprovalSignature, + const tx = coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + takerAddress, + transaction.signature, + [], + [], + { + from: takerAddress, + gas: constants.MAX_EXECUTE_TRANSACTION_GAS, + }, + ); + + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, feeRecipientAddress), ); }); it(`${fnName} should revert with an invalid approval signature`, async () => { @@ -233,16 +233,18 @@ describe('Coordinator tests', () => { approvalExpirationTimeSeconds, ); const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`; - await expectTransactionFailedAsync( - coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - takerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [signature], - { from: takerAddress }, - ), - RevertReason.InvalidApprovalSignature, + const tx = coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + takerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [signature], + { from: takerAddress }, + ); + + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, feeRecipientAddress), ); }); it(`${fnName} should revert with an expired approval`, async () => { @@ -256,16 +258,19 @@ describe('Coordinator tests', () => { takerAddress, approvalExpirationTimeSeconds, ); - await expectTransactionFailedAsync( - coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - takerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval.signature], - { from: takerAddress }, - ), - RevertReason.ApprovalExpired, + + const tx = coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + takerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.signature], + { from: takerAddress }, + ); + + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.ApprovalExpiredError(transactionHash, approvalExpirationTimeSeconds), ); }); it(`${fnName} should revert if not called by tx signer or approver`, async () => { @@ -279,17 +284,16 @@ describe('Coordinator tests', () => { takerAddress, approvalExpirationTimeSeconds, ); - await expectTransactionFailedAsync( - coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - takerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval.signature], - { from: owner }, - ), - RevertReason.InvalidOrigin, + + const tx = coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + takerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.signature], + { from: owner }, ); + expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(takerAddress)); }); } }); @@ -306,69 +310,35 @@ describe('Coordinator tests', () => { takerAddress, approvalExpirationTimeSeconds, ); - const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - takerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval.signature], - { from: takerAddress, gas: constants.MAX_EXECUTE_TRANSACTION_GAS }, - ), + const transactionReceipt = await coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + takerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.signature], + { from: takerAddress, gas: constants.MAX_EXECUTE_TRANSACTION_GAS }, constants.AWAIT_TRANSACTION_MINED_MS, ); - const fillLogs = transactionReceipt.logs.filter( - log => (log as LogWithDecodedArgs).event === 'Fill', - ); - expect(fillLogs.length).to.eq(orders.length); - orders.forEach((order, index) => { - const fillLogArgs = (fillLogs[index] as LogWithDecodedArgs).args; - expect(fillLogArgs.makerAddress).to.eq(makerAddress); - expect(fillLogArgs.takerAddress).to.eq(takerAddress); - expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address); - expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); - expect(fillLogArgs.makerAssetData).to.eq(order.makerAssetData); - expect(fillLogArgs.takerAssetData).to.eq(order.takerAssetData); - expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(order.makerAssetAmount); - expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(order.takerAssetAmount); - expect(fillLogArgs.makerFeePaid).to.bignumber.eq(order.makerFee); - expect(fillLogArgs.takerFeePaid).to.bignumber.eq(order.takerFee); - expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order)); - }); + + const expectedEvents = orders.map(order => expectedFillEvent(order)); + verifyEvents(transactionReceipt, expectedEvents, ExchangeEvents.Fill); }); it(`${fnName} should fill the orders if called by approver`, async () => { const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); - const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - feeRecipientAddress, - transaction.signature, - [], - [], - { from: feeRecipientAddress, gas: constants.MAX_EXECUTE_TRANSACTION_GAS }, - ), + const transactionReceipt = await coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + feeRecipientAddress, + transaction.signature, + [], + [], + { from: feeRecipientAddress, gas: constants.MAX_EXECUTE_TRANSACTION_GAS }, constants.AWAIT_TRANSACTION_MINED_MS, ); - const fillLogs = transactionReceipt.logs.filter( - log => (log as LogWithDecodedArgs).event === 'Fill', - ); - expect(fillLogs.length).to.eq(orders.length); - orders.forEach((order, index) => { - const fillLogArgs = (fillLogs[index] as LogWithDecodedArgs).args; - expect(fillLogArgs.makerAddress).to.eq(makerAddress); - expect(fillLogArgs.takerAddress).to.eq(takerAddress); - expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address); - expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); - expect(fillLogArgs.makerAssetData).to.eq(order.makerAssetData); - expect(fillLogArgs.takerAssetData).to.eq(order.takerAssetData); - expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(order.makerAssetAmount); - expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(order.takerAssetAmount); - expect(fillLogArgs.makerFeePaid).to.bignumber.eq(order.makerFee); - expect(fillLogArgs.takerFeePaid).to.bignumber.eq(order.takerFee); - expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order)); - }); + + const expectedEvents = orders.map(order => expectedFillEvent(order)); + verifyEvents(transactionReceipt, expectedEvents, ExchangeEvents.Fill); }); it(`${fnName} should revert with an invalid approval signature`, async () => { const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; @@ -382,16 +352,18 @@ describe('Coordinator tests', () => { approvalExpirationTimeSeconds, ); const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`; - await expectTransactionFailedAsync( - coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - takerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [signature], - { from: takerAddress }, - ), - RevertReason.InvalidApprovalSignature, + const tx = coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + takerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [signature], + { from: takerAddress }, + ); + + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, feeRecipientAddress), ); }); it(`${fnName} should revert with an expired approval`, async () => { @@ -405,16 +377,18 @@ describe('Coordinator tests', () => { takerAddress, approvalExpirationTimeSeconds, ); - await expectTransactionFailedAsync( - coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - takerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval.signature], - { from: takerAddress }, - ), - RevertReason.ApprovalExpired, + const tx = coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + takerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.signature], + { from: takerAddress }, + ); + + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.ApprovalExpiredError(transactionHash, approvalExpirationTimeSeconds), ); }); it(`${fnName} should revert if not called by tx signer or approver`, async () => { @@ -428,17 +402,16 @@ describe('Coordinator tests', () => { takerAddress, approvalExpirationTimeSeconds, ); - await expectTransactionFailedAsync( - coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - takerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval.signature], - { from: owner }, - ), - RevertReason.InvalidOrigin, + + const tx = coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + takerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.signature], + { from: owner }, ); + expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(takerAddress)); }); } }); @@ -447,84 +420,55 @@ describe('Coordinator tests', () => { const orders = [await orderFactory.newSignedOrderAsync()]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders); const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data }); - const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - makerAddress, - transaction.signature, - [], - [], - { - from: makerAddress, - }, - ), + const transactionReceipt = await coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + makerAddress, + transaction.signature, + [], + [], + { + from: makerAddress, + }, ); - const cancelLogs = transactionReceipt.logs.filter( - log => (log as LogWithDecodedArgs).event === 'Cancel', - ); - expect(cancelLogs.length).to.eq(1); - const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs).args; - expect(cancelLogArgs.makerAddress).to.eq(makerAddress); - expect(cancelLogArgs.senderAddress).to.eq(coordinatorContract.address); - expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); - expect(cancelLogArgs.makerAssetData).to.eq(orders[0].makerAssetData); - expect(cancelLogArgs.takerAssetData).to.eq(orders[0].takerAssetData); - expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0])); + verifyEvents(transactionReceipt, [expectedCancelEvent(orders[0])], ExchangeEvents.Cancel); }); it('batchCancelOrders call should be successful without an approval', async () => { const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.BatchCancelOrders, orders); const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data }); - const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - makerAddress, - transaction.signature, - [], - [], - { - from: makerAddress, - }, - ), + const transactionReceipt = await coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + makerAddress, + transaction.signature, + [], + [], + { + from: makerAddress, + }, ); - const cancelLogs = transactionReceipt.logs.filter( - log => (log as LogWithDecodedArgs).event === 'Cancel', - ); - expect(cancelLogs.length).to.eq(orders.length); - orders.forEach((order, index) => { - const cancelLogArgs = (cancelLogs[index] as LogWithDecodedArgs).args; - expect(cancelLogArgs.makerAddress).to.eq(makerAddress); - expect(cancelLogArgs.senderAddress).to.eq(coordinatorContract.address); - expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress); - expect(cancelLogArgs.makerAssetData).to.eq(order.makerAssetData); - expect(cancelLogArgs.takerAssetData).to.eq(order.takerAssetData); - expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order)); - }); + const expectedEvents = orders.map(order => expectedCancelEvent(order)); + verifyEvents(transactionReceipt, expectedEvents, ExchangeEvents.Cancel); }); it('cancelOrdersUpTo call should be successful without an approval', async () => { const targetEpoch = constants.ZERO_AMOUNT; const data = exchange.cancelOrdersUpTo.getABIEncodedTransactionData(targetEpoch); const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data }); - const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync( - await coordinatorContract.executeTransaction.sendTransactionAsync( - transaction, - makerAddress, - transaction.signature, - [], - [], - { - from: makerAddress, - }, - ), + const transactionReceipt = await coordinatorContract.executeTransaction.awaitTransactionSuccessAsync( + transaction, + makerAddress, + transaction.signature, + [], + [], + { + from: makerAddress, + }, ); - const cancelLogs = transactionReceipt.logs.filter( - log => (log as LogWithDecodedArgs).event === 'CancelUpTo', - ); - expect(cancelLogs.length).to.eq(1); - const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs).args; - expect(cancelLogArgs.makerAddress).to.eq(makerAddress); - expect(cancelLogArgs.orderSenderAddress).to.eq(coordinatorContract.address); - expect(cancelLogArgs.orderEpoch).to.bignumber.eq(targetEpoch.plus(1)); + const expectedEvent: ExchangeCancelUpToEventArgs = { + makerAddress, + orderSenderAddress: coordinatorContract.address, + orderEpoch: targetEpoch.plus(1), + }; + verifyEvents(transactionReceipt, [expectedEvent], ExchangeEvents.CancelUpTo); }); }); }); diff --git a/contracts/coordinator/test/coordinator_registry.ts b/contracts/coordinator/test/coordinator_registry.ts index c9404cc939..f3830f4d86 100644 --- a/contracts/coordinator/test/coordinator_registry.ts +++ b/contracts/coordinator/test/coordinator_registry.ts @@ -1,44 +1,25 @@ -import { artifacts as exchangeArtifacts } from '@0x/contracts-exchange'; -import { chaiSetup, provider, web3Wrapper } from '@0x/contracts-test-utils'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import * as chai from 'chai'; +import { blockchainTests, expect } from '@0x/contracts-test-utils'; import { LogWithDecodedArgs } from 'ethereum-types'; import { CoordinatorRegistryCoordinatorEndpointSetEventArgs } from '../src'; import { CoordinatorRegistryWrapper } from './utils/coordinator_registry_wrapper'; -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -web3Wrapper.abiDecoder.addABI(exchangeArtifacts.Exchange.compilerOutput.abi); // tslint:disable:no-unnecessary-type-assertion -describe('Coordinator Registry tests', () => { +blockchainTests.resets('Coordinator Registry tests', env => { let coordinatorOperator: string; const coordinatorEndpoint = 'http://sometec.0x.org'; const nilCoordinatorEndpoint = ''; let coordinatorRegistryWrapper: CoordinatorRegistryWrapper; // tests - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); before(async () => { // setup accounts (skip owner) - const accounts = await web3Wrapper.getAvailableAddressesAsync(); + const accounts = await env.getAccountAddressesAsync(); [, coordinatorOperator] = accounts; // deploy coordinator registry - coordinatorRegistryWrapper = new CoordinatorRegistryWrapper(provider); + coordinatorRegistryWrapper = new CoordinatorRegistryWrapper(env.provider); await coordinatorRegistryWrapper.deployCoordinatorRegistryAsync(); }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); describe('core', () => { it('Should successfully set a Coordinator endpoint', async () => { await coordinatorRegistryWrapper.setCoordinatorEndpointAsync(coordinatorOperator, coordinatorEndpoint); diff --git a/contracts/coordinator/test/libs.ts b/contracts/coordinator/test/libs.ts index 3d9715dcee..5e32e55486 100644 --- a/contracts/coordinator/test/libs.ts +++ b/contracts/coordinator/test/libs.ts @@ -1,66 +1,31 @@ -import { chaiSetup, constants, provider, randomAddress, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; -import { BlockchainLifecycle } from '@0x/dev-utils'; +import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils'; import { transactionHashUtils } from '@0x/order-utils'; -import { BigNumber, providerUtils } from '@0x/utils'; -import * as chai from 'chai'; +import { BigNumber } from '@0x/utils'; import { artifacts, CoordinatorContract, hashUtils } from '../src'; -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('Libs tests', () => { +blockchainTests.resets('Libs tests', env => { let coordinatorContract: CoordinatorContract; let chainId: number; const exchangeAddress = randomAddress(); before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - chainId = await providerUtils.getChainIdAsync(provider); + chainId = await env.getChainIdAsync(); coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync( artifacts.Coordinator, - provider, - txDefaults, + env.provider, + env.txDefaults, artifacts, exchangeAddress, new BigNumber(chainId), ); }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - - describe('getTransactionHash', () => { - it('should return the correct transaction hash', async () => { - const tx = { - salt: new BigNumber(0), - expirationTimeSeconds: new BigNumber(0), - signerAddress: constants.NULL_ADDRESS, - data: '0x1234', - domain: { - verifyingContract: exchangeAddress, - chainId, - }, - }; - const expectedTxHash = transactionHashUtils.getTransactionHashHex(tx); - const txHash = await coordinatorContract.getTransactionHash.callAsync(tx); - expect(expectedTxHash).to.eq(txHash); - }); - }); describe('getApprovalHash', () => { it('should return the correct approval hash', async () => { const signedTx = { salt: new BigNumber(0), + gasPrice: new BigNumber(0), expirationTimeSeconds: new BigNumber(0), signerAddress: constants.NULL_ADDRESS, data: '0x1234', diff --git a/contracts/coordinator/test/mixins.ts b/contracts/coordinator/test/mixins.ts index 6394b4e12b..50b1d63c44 100644 --- a/contracts/coordinator/test/mixins.ts +++ b/contracts/coordinator/test/mixins.ts @@ -1,29 +1,20 @@ import { constants as exchangeConstants, exchangeDataEncoder, ExchangeFunctionName } from '@0x/contracts-exchange'; import { - chaiSetup, + blockchainTests, constants, - expectContractCallFailedAsync, + expect, getLatestBlockTimestampAsync, - provider, randomAddress, TransactionFactory, - txDefaults, - web3Wrapper, } from '@0x/contracts-test-utils'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { transactionHashUtils } from '@0x/order-utils'; -import { RevertReason, SignatureType, SignedOrder } from '@0x/types'; -import { BigNumber, LibBytesRevertErrors, providerUtils } from '@0x/utils'; -import * as chai from 'chai'; +import { CoordinatorRevertErrors, transactionHashUtils } from '@0x/order-utils'; +import { SignatureType, SignedOrder } from '@0x/types'; +import { BigNumber, LibBytesRevertErrors } from '@0x/utils'; import * as ethUtil from 'ethereumjs-util'; import { ApprovalFactory, artifacts, CoordinatorContract } from '../src'; -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('Mixins tests', () => { +blockchainTests.resets('Mixins tests', env => { let chainId: number; let transactionSignerAddress: string; let approvalSignerAddress1: string; @@ -36,23 +27,17 @@ describe('Mixins tests', () => { const exchangeAddress = randomAddress(); before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - chainId = await providerUtils.getChainIdAsync(provider); + chainId = await env.getChainIdAsync(); mixins = await CoordinatorContract.deployFrom0xArtifactAsync( artifacts.Coordinator, - provider, - txDefaults, + env.provider, + env.txDefaults, artifacts, exchangeAddress, new BigNumber(chainId), ); - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts.slice(0, 3); + const accounts = await env.getAccountAddressesAsync(); + [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts; defaultOrder = { makerAddress: constants.NULL_ADDRESS, takerAddress: constants.NULL_ADDRESS, @@ -79,12 +64,6 @@ describe('Mixins tests', () => { approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1, mixins.address); approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2, mixins.address); }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); describe('getSignerAddress', () => { it('should return the correct address using the EthSign signature type', async () => { @@ -110,8 +89,12 @@ describe('Mixins tests', () => { transaction.signature.length - 2, )}${illegalSignatureByte}`; const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith( - RevertReason.SignatureIllegal, + expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith( + new CoordinatorRevertErrors.SignatureError( + CoordinatorRevertErrors.SignatureErrorCodes.Illegal, + transactionHash, + transaction.signature, + ), ); }); it('should revert with with the Invalid signature type', async () => { @@ -120,8 +103,12 @@ describe('Mixins tests', () => { const invalidSignatureByte = ethUtil.toBuffer(SignatureType.Invalid).toString('hex'); transaction.signature = `0x${invalidSignatureByte}`; const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith( - RevertReason.SignatureInvalid, + expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith( + new CoordinatorRevertErrors.SignatureError( + CoordinatorRevertErrors.SignatureErrorCodes.Invalid, + transactionHash, + transaction.signature, + ), ); }); it("should revert with with a signature type that doesn't exist", async () => { @@ -133,8 +120,12 @@ describe('Mixins tests', () => { transaction.signature.length - 2, )}${invalidSignatureByte}`; const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); - expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.be.rejectedWith( - RevertReason.SignatureUnsupported, + expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith( + new CoordinatorRevertErrors.SignatureError( + CoordinatorRevertErrors.SignatureErrorCodes.Unsupported, + transactionHash, + transaction.signature, + ), ); }); }); @@ -320,16 +311,18 @@ describe('Mixins tests', () => { approvalExpirationTimeSeconds, ); const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`; - expectContractCallFailedAsync( - mixins.assertValidCoordinatorApprovals.callAsync( - transaction, - transactionSignerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [signature], - { from: transactionSignerAddress }, - ), - RevertReason.InvalidApprovalSignature, + const tx = mixins.assertValidCoordinatorApprovals.callAsync( + transaction, + transactionSignerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [signature], + { from: transactionSignerAddress }, + ); + + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), ); }); it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => { @@ -343,16 +336,18 @@ describe('Mixins tests', () => { transactionSignerAddress, approvalExpirationTimeSeconds, ); - expectContractCallFailedAsync( - mixins.assertValidCoordinatorApprovals.callAsync( - transaction, - transactionSignerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval.signature], - { from: transactionSignerAddress }, - ), - RevertReason.ApprovalExpired, + const tx = mixins.assertValidCoordinatorApprovals.callAsync( + transaction, + transactionSignerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.signature], + { from: transactionSignerAddress }, + ); + + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.ApprovalExpiredError(transactionHash, approvalExpirationTimeSeconds), ); }); it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => { @@ -366,17 +361,16 @@ describe('Mixins tests', () => { transactionSignerAddress, approvalExpirationTimeSeconds, ); - expectContractCallFailedAsync( - mixins.assertValidCoordinatorApprovals.callAsync( - transaction, - transactionSignerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval.signature], - { from: approvalSignerAddress2 }, - ), - RevertReason.InvalidOrigin, + + const tx = mixins.assertValidCoordinatorApprovals.callAsync( + transaction, + transactionSignerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval.signature], + { from: approvalSignerAddress2 }, ); + expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); }); } }); @@ -514,32 +508,33 @@ describe('Mixins tests', () => { transactionSignerAddress, approvalExpirationTimeSeconds, ); - expectContractCallFailedAsync( - mixins.assertValidCoordinatorApprovals.callAsync( - transaction, - transactionSignerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval2.signature], - { from: approvalSignerAddress1 }, - ), - RevertReason.InvalidOrigin, + + const tx = mixins.assertValidCoordinatorApprovals.callAsync( + transaction, + transactionSignerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval2.signature], + { from: approvalSignerAddress1 }, ); + expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); }); it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[], expiration=[]`, async () => { const orders = [defaultOrder, defaultOrder]; const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const transaction = await transactionFactory.newSignedTransactionAsync({ data }); - expectContractCallFailedAsync( - mixins.assertValidCoordinatorApprovals.callAsync( - transaction, - transactionSignerAddress, - transaction.signature, - [], - [], - { from: transactionSignerAddress }, - ), - RevertReason.InvalidApprovalSignature, + const tx = mixins.assertValidCoordinatorApprovals.callAsync( + transaction, + transactionSignerAddress, + transaction.signature, + [], + [], + { from: transactionSignerAddress }, + ); + + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), ); }); it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[invalid], expiration=[valid]`, async () => { @@ -554,16 +549,18 @@ describe('Mixins tests', () => { approvalExpirationTimeSeconds, ); const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`; - expectContractCallFailedAsync( - mixins.assertValidCoordinatorApprovals.callAsync( - transaction, - transactionSignerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [signature], - { from: transactionSignerAddress }, - ), - RevertReason.InvalidApprovalSignature, + const tx = mixins.assertValidCoordinatorApprovals.callAsync( + transaction, + transactionSignerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [signature], + { from: transactionSignerAddress }, + ); + + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), ); }); it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,invalid], expiration=[valid,valid]`, async () => { @@ -583,16 +580,18 @@ describe('Mixins tests', () => { approvalExpirationTimeSeconds, ); const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`; - expectContractCallFailedAsync( - mixins.assertValidCoordinatorApprovals.callAsync( - transaction, - transactionSignerAddress, - transaction.signature, - [approvalExpirationTimeSeconds, approvalExpirationTimeSeconds], - [approval1.signature, approvalSignature2], - { from: transactionSignerAddress }, - ), - RevertReason.InvalidApprovalSignature, + const tx = mixins.assertValidCoordinatorApprovals.callAsync( + transaction, + transactionSignerAddress, + transaction.signature, + [approvalExpirationTimeSeconds, approvalExpirationTimeSeconds], + [approval1.signature, approvalSignature2], + { from: transactionSignerAddress }, + ); + + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2), ); }); it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[invalid], expiration=[valid]`, async () => { @@ -607,16 +606,18 @@ describe('Mixins tests', () => { approvalExpirationTimeSeconds, ); const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`; - expectContractCallFailedAsync( - mixins.assertValidCoordinatorApprovals.callAsync( - transaction, - approvalSignerAddress1, - transaction.signature, - [approvalExpirationTimeSeconds], - [approvalSignature2], - { from: approvalSignerAddress1 }, - ), - RevertReason.InvalidApprovalSignature, + const tx = mixins.assertValidCoordinatorApprovals.callAsync( + transaction, + approvalSignerAddress1, + transaction.signature, + [approvalExpirationTimeSeconds], + [approvalSignature2], + { from: approvalSignerAddress1 }, + ); + + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2), ); }); it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,valid], expiration=[valid,invalid]`, async () => { @@ -636,16 +637,18 @@ describe('Mixins tests', () => { transactionSignerAddress, approvalExpirationTimeSeconds2, ); - expectContractCallFailedAsync( - mixins.assertValidCoordinatorApprovals.callAsync( - transaction, - transactionSignerAddress, - transaction.signature, - [approvalExpirationTimeSeconds1, approvalExpirationTimeSeconds2], - [approval1.signature, approval2.signature], - { from: transactionSignerAddress }, - ), - RevertReason.ApprovalExpired, + + const tx = mixins.assertValidCoordinatorApprovals.callAsync( + transaction, + transactionSignerAddress, + transaction.signature, + [approvalExpirationTimeSeconds1, approvalExpirationTimeSeconds2], + [approval1.signature, approval2.signature], + { from: transactionSignerAddress }, + ); + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.ApprovalExpiredError(transactionHash, approvalExpirationTimeSeconds2), ); }); it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid], expiration=[invalid]`, async () => { @@ -659,16 +662,18 @@ describe('Mixins tests', () => { transactionSignerAddress, approvalExpirationTimeSeconds, ); - expectContractCallFailedAsync( - mixins.assertValidCoordinatorApprovals.callAsync( - transaction, - approvalSignerAddress1, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval2.signature], - { from: approvalSignerAddress1 }, - ), - RevertReason.ApprovalExpired, + + const tx = mixins.assertValidCoordinatorApprovals.callAsync( + transaction, + approvalSignerAddress1, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval2.signature], + { from: approvalSignerAddress1 }, + ); + const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); + expect(tx).to.revertWith( + new CoordinatorRevertErrors.ApprovalExpiredError(transactionHash, approvalExpirationTimeSeconds), ); }); it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid], expiration=[valid]`, async () => { @@ -682,17 +687,16 @@ describe('Mixins tests', () => { transactionSignerAddress, approvalExpirationTimeSeconds, ); - expectContractCallFailedAsync( - mixins.assertValidCoordinatorApprovals.callAsync( - transaction, - transactionSignerAddress, - transaction.signature, - [approvalExpirationTimeSeconds], - [approval1.signature], - { from: approvalSignerAddress2 }, - ), - RevertReason.InvalidOrigin, + + const tx = mixins.assertValidCoordinatorApprovals.callAsync( + transaction, + transactionSignerAddress, + transaction.signature, + [approvalExpirationTimeSeconds], + [approval1.signature], + { from: approvalSignerAddress2 }, ); + expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); }); } }); diff --git a/contracts/coordinator/test/utils/coordinator_registry_wrapper.ts b/contracts/coordinator/test/utils/coordinator_registry_wrapper.ts index 3d7a2999ef..a31d90b03b 100644 --- a/contracts/coordinator/test/utils/coordinator_registry_wrapper.ts +++ b/contracts/coordinator/test/utils/coordinator_registry_wrapper.ts @@ -1,3 +1,4 @@ +import { artifacts as exchangeArtifacts } from '@0x/contracts-exchange'; import { LogDecoder, txDefaults } from '@0x/contracts-test-utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types'; @@ -17,7 +18,7 @@ export class CoordinatorRegistryWrapper { constructor(provider: ZeroExProvider) { this._web3Wrapper = new Web3Wrapper(provider); this._provider = provider; - this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); + this._logDecoder = new LogDecoder(this._web3Wrapper, { ...exchangeArtifacts, ...artifacts }); } public async deployCoordinatorRegistryAsync(): Promise { this._coordinatorRegistryContract = await CoordinatorRegistryContract.deployFrom0xArtifactAsync( diff --git a/contracts/coordinator/tsconfig.json b/contracts/coordinator/tsconfig.json index ba2c48b6cd..8db06e4dd6 100644 --- a/contracts/coordinator/tsconfig.json +++ b/contracts/coordinator/tsconfig.json @@ -2,6 +2,21 @@ "extends": "../../tsconfig", "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], - "files": ["generated-artifacts/Coordinator.json", "generated-artifacts/CoordinatorRegistry.json"], + "files": [ + "generated-artifacts/Coordinator.json", + "generated-artifacts/CoordinatorRegistry.json", + "generated-artifacts/ICoordinatorApprovalVerifier.json", + "generated-artifacts/ICoordinatorCore.json", + "generated-artifacts/ICoordinatorRegistryCore.json", + "generated-artifacts/ICoordinatorSignatureValidator.json", + "generated-artifacts/LibConstants.json", + "generated-artifacts/LibCoordinatorApproval.json", + "generated-artifacts/LibCoordinatorRichErrors.json", + "generated-artifacts/LibEIP712CoordinatorDomain.json", + "generated-artifacts/MixinCoordinatorApprovalVerifier.json", + "generated-artifacts/MixinCoordinatorCore.json", + "generated-artifacts/MixinCoordinatorRegistryCore.json", + "generated-artifacts/MixinSignatureValidator.json" + ], "exclude": ["./deploy/solc/solc_bin"] } diff --git a/packages/order-utils/src/constants.ts b/packages/order-utils/src/constants.ts index 8ab303343d..8c6fd8d9a1 100644 --- a/packages/order-utils/src/constants.ts +++ b/packages/order-utils/src/constants.ts @@ -140,7 +140,7 @@ export const constants = { ], }, COORDINATOR_DOMAIN_NAME: '0x Protocol Coordinator', - COORDINATOR_DOMAIN_VERSION: '2.0.0', + COORDINATOR_DOMAIN_VERSION: '3.0.0', COORDINATOR_APPROVAL_SCHEMA: { name: 'CoordinatorApproval', parameters: [ diff --git a/packages/order-utils/src/coordinator_revert_errors.ts b/packages/order-utils/src/coordinator_revert_errors.ts index e97831c555..4433790a8e 100644 --- a/packages/order-utils/src/coordinator_revert_errors.ts +++ b/packages/order-utils/src/coordinator_revert_errors.ts @@ -34,17 +34,17 @@ export class ApprovalExpiredError extends RevertError { } } -export class InvalidApprovalSignature extends RevertError { +export class InvalidApprovalSignatureError extends RevertError { constructor(transactionHash?: string, approverAddress?: string) { super( - 'InvalidApprovalSignature', - 'InvalidApprovalSignature(bytes32 transactionHash, address approverAddress)', + 'InvalidApprovalSignatureError', + 'InvalidApprovalSignatureError(bytes32 transactionHash, address approverAddress)', { transactionHash, approverAddress }, ); } } -const types = [SignatureError, InvalidOriginError, ApprovalExpiredError, InvalidApprovalSignature]; +const types = [SignatureError, InvalidOriginError, ApprovalExpiredError, InvalidApprovalSignatureError]; // Register the types we've defined. for (const type of types) { diff --git a/packages/order-utils/src/eip712_utils.ts b/packages/order-utils/src/eip712_utils.ts index d6972557c8..2b9404cc65 100644 --- a/packages/order-utils/src/eip712_utils.ts +++ b/packages/order-utils/src/eip712_utils.ts @@ -95,7 +95,7 @@ export const eip712Utils = { return typedData; }, /** - * Creates an Coordiantor typedData EIP712TypedData object for use with the Coordinator extension contract + * Creates an Coordinator typedData EIP712TypedData object for use with the Coordinator extension contract * @param transaction A 0x transaction * @param verifyingContract The coordinator extension contract address that will be verifying the typedData * @param txOrigin The desired `tx.origin` that should be able to submit an Ethereum txn involving this 0x transaction diff --git a/packages/order-utils/src/index.ts b/packages/order-utils/src/index.ts index 1898f219c0..3b20d0ea14 100644 --- a/packages/order-utils/src/index.ts +++ b/packages/order-utils/src/index.ts @@ -1,3 +1,4 @@ +export import CoordinatorRevertErrors = require('./coordinator_revert_errors'); export import ExchangeRevertErrors = require('./exchange_revert_errors'); export import ForwarderRevertErrors = require('./forwarder_revert_errors'); export import LibMathRevertErrors = require('./lib_math_revert_errors');