aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Evans <dekz@dekz.net>2018-08-16 10:13:27 +0800
committerGitHub <noreply@github.com>2018-08-16 10:13:27 +0800
commit480d28ea26be86d685d81059a0dbe4cd025f0c21 (patch)
tree8b8b72f1945a7d85f11af14f16338a059cc9f900
parentf9f232f5d9527926cd64027f69491b0bc6e58894 (diff)
parent88c99396a2d1b880bffb21ef19507d02b474ba9b (diff)
downloaddexon-sol-tools-480d28ea26be86d685d81059a0dbe4cd025f0c21.tar
dexon-sol-tools-480d28ea26be86d685d81059a0dbe4cd025f0c21.tar.gz
dexon-sol-tools-480d28ea26be86d685d81059a0dbe4cd025f0c21.tar.bz2
dexon-sol-tools-480d28ea26be86d685d81059a0dbe4cd025f0c21.tar.lz
dexon-sol-tools-480d28ea26be86d685d81059a0dbe4cd025f0c21.tar.xz
dexon-sol-tools-480d28ea26be86d685d81059a0dbe4cd025f0c21.tar.zst
dexon-sol-tools-480d28ea26be86d685d81059a0dbe4cd025f0c21.zip
Merge pull request #959 from 0xProject/bug/order-utils/rounding-error-small-maker
[Order-utils] Order is valid when maker amount is very small
-rw-r--r--packages/contracts/test/exchange/fill_order.ts11
-rw-r--r--packages/contracts/test/utils/fill_order_combinatorial_utils.ts7
-rw-r--r--packages/contracts/test/utils/order_factory_from_scenario.ts23
-rw-r--r--packages/contracts/test/utils/types.ts3
-rw-r--r--packages/order-utils/CHANGELOG.json4
-rw-r--r--packages/order-utils/src/order_state_utils.ts95
-rw-r--r--packages/order-utils/test/order_state_utils_test.ts124
-rw-r--r--packages/order-watcher/test/order_watcher_test.ts20
-rw-r--r--packages/types/src/index.ts3
-rw-r--r--packages/website/ts/utils/utils.ts7
10 files changed, 232 insertions, 65 deletions
diff --git a/packages/contracts/test/exchange/fill_order.ts b/packages/contracts/test/exchange/fill_order.ts
index 1494fe093..e79e2239e 100644
--- a/packages/contracts/test/exchange/fill_order.ts
+++ b/packages/contracts/test/exchange/fill_order.ts
@@ -104,6 +104,17 @@ describe('FillOrder Tests', () => {
};
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
});
+ it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount with zero decimals', async () => {
+ const fillScenario = {
+ ...defaultFillScenario,
+ orderScenario: {
+ ...defaultFillScenario.orderScenario,
+ makerAssetAmountScenario: OrderAssetAmountScenario.Small,
+ makerAssetDataScenario: AssetDataScenario.ERC20ZeroDecimals,
+ },
+ };
+ await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
+ });
it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => {
const fillScenario = {
...defaultFillScenario,
diff --git a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts
index 284c4a2db..f18ad0dd3 100644
--- a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts
+++ b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts
@@ -81,6 +81,12 @@ export async function fillOrderCombinatorialUtilsFactoryAsync(
erc20FiveDecimalTokenCount,
fiveDecimals,
);
+ const zeroDecimals = new BigNumber(0);
+ const erc20ZeroDecimalTokenCount = 2;
+ const [erc20ZeroDecimalTokenA, erc20ZeroDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync(
+ erc20ZeroDecimalTokenCount,
+ zeroDecimals,
+ );
const erc20Proxy = await erc20Wrapper.deployProxyAsync();
await erc20Wrapper.setBalancesAndAllowancesAsync();
@@ -119,6 +125,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync(
zrxToken.address,
[erc20EighteenDecimalTokenA.address, erc20EighteenDecimalTokenB.address],
[erc20FiveDecimalTokenA.address, erc20FiveDecimalTokenB.address],
+ [erc20ZeroDecimalTokenA.address, erc20ZeroDecimalTokenB.address],
erc721Token,
erc721Balances,
exchangeContract.address,
diff --git a/packages/contracts/test/utils/order_factory_from_scenario.ts b/packages/contracts/test/utils/order_factory_from_scenario.ts
index a908140b9..8e04db588 100644
--- a/packages/contracts/test/utils/order_factory_from_scenario.ts
+++ b/packages/contracts/test/utils/order_factory_from_scenario.ts
@@ -21,6 +21,8 @@ const POINT_ONE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(100_000_000_000_000_000)
const POINT_ZERO_FIVE_UNITS_EIGHTEEN_DECIMALS = new BigNumber(50_000_000_000_000_000);
const TEN_UNITS_FIVE_DECIMALS = new BigNumber(1_000_000);
const FIVE_UNITS_FIVE_DECIMALS = new BigNumber(500_000);
+const TEN_UNITS_ZERO_DECIMALS = new BigNumber(10);
+const ONE_THOUSAND_UNITS_ZERO_DECIMALS = new BigNumber(1000);
const ONE_NFT_UNIT = new BigNumber(1);
export class OrderFactoryFromScenario {
@@ -28,6 +30,7 @@ export class OrderFactoryFromScenario {
private readonly _zrxAddress: string;
private readonly _nonZrxERC20EighteenDecimalTokenAddresses: string[];
private readonly _erc20FiveDecimalTokenAddresses: string[];
+ private readonly _erc20ZeroDecimalTokenAddresses: string[];
private readonly _erc721Token: DummyERC721TokenContract;
private readonly _erc721Balances: ERC721TokenIdsByOwner;
private readonly _exchangeAddress: string;
@@ -36,6 +39,7 @@ export class OrderFactoryFromScenario {
zrxAddress: string,
nonZrxERC20EighteenDecimalTokenAddresses: string[],
erc20FiveDecimalTokenAddresses: string[],
+ erc20ZeroDecimalTokenAddresses: string[],
erc721Token: DummyERC721TokenContract,
erc721Balances: ERC721TokenIdsByOwner,
exchangeAddress: string,
@@ -44,6 +48,7 @@ export class OrderFactoryFromScenario {
this._zrxAddress = zrxAddress;
this._nonZrxERC20EighteenDecimalTokenAddresses = nonZrxERC20EighteenDecimalTokenAddresses;
this._erc20FiveDecimalTokenAddresses = erc20FiveDecimalTokenAddresses;
+ this._erc20ZeroDecimalTokenAddresses = erc20ZeroDecimalTokenAddresses;
this._erc721Token = erc721Token;
this._erc721Balances = erc721Balances;
this._exchangeAddress = exchangeAddress;
@@ -89,6 +94,9 @@ export class OrderFactoryFromScenario {
erc721MakerAssetIds[0],
);
break;
+ case AssetDataScenario.ERC20ZeroDecimals:
+ makerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[0]);
+ break;
default:
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
}
@@ -109,6 +117,9 @@ export class OrderFactoryFromScenario {
erc721TakerAssetIds[0],
);
break;
+ case AssetDataScenario.ERC20ZeroDecimals:
+ takerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[1]);
+ break;
default:
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
}
@@ -126,6 +137,9 @@ export class OrderFactoryFromScenario {
case AssetDataScenario.ERC721:
makerAssetAmount = ONE_NFT_UNIT;
break;
+ case AssetDataScenario.ERC20ZeroDecimals:
+ makerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS;
+ break;
default:
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
}
@@ -142,6 +156,9 @@ export class OrderFactoryFromScenario {
case AssetDataScenario.ERC721:
makerAssetAmount = ONE_NFT_UNIT;
break;
+ case AssetDataScenario.ERC20ZeroDecimals:
+ makerAssetAmount = TEN_UNITS_ZERO_DECIMALS;
+ break;
default:
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
}
@@ -166,6 +183,9 @@ export class OrderFactoryFromScenario {
case AssetDataScenario.ERC721:
takerAssetAmount = ONE_NFT_UNIT;
break;
+ case AssetDataScenario.ERC20ZeroDecimals:
+ takerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS;
+ break;
default:
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
}
@@ -182,6 +202,9 @@ export class OrderFactoryFromScenario {
case AssetDataScenario.ERC721:
takerAssetAmount = ONE_NFT_UNIT;
break;
+ case AssetDataScenario.ERC20ZeroDecimals:
+ takerAssetAmount = TEN_UNITS_ZERO_DECIMALS;
+ break;
default:
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
}
diff --git a/packages/contracts/test/utils/types.ts b/packages/contracts/test/utils/types.ts
index 67313b647..481ee87d6 100644
--- a/packages/contracts/test/utils/types.ts
+++ b/packages/contracts/test/utils/types.ts
@@ -177,10 +177,11 @@ export enum ExpirationTimeSecondsScenario {
}
export enum AssetDataScenario {
- ERC721 = 'ERC721',
+ ERC20ZeroDecimals = 'ERC20_ZERO_DECIMALS',
ZRXFeeToken = 'ZRX_FEE_TOKEN',
ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS',
ERC20NonZRXEighteenDecimals = 'ERC20_NON_ZRX_EIGHTEEN_DECIMALS',
+ ERC721 = 'ERC721',
}
export enum TakerAssetFillAmountScenario {
diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json
index 6b49d2ee6..86f0da65a 100644
--- a/packages/order-utils/CHANGELOG.json
+++ b/packages/order-utils/CHANGELOG.json
@@ -3,6 +3,10 @@
"version": "1.0.1-rc.4",
"changes": [
{
+ "note": "Remove rounding error being thrown when maker amount is very small",
+ "pr": 959
+ },
+ {
"note": "Added rateUtils and sortingUtils",
"pr": 953
},
diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts
index 189bf4180..18fc18bf6 100644
--- a/packages/order-utils/src/order_state_utils.ts
+++ b/packages/order-utils/src/order_state_utils.ts
@@ -11,6 +11,7 @@ import { BigNumber } from '@0xproject/utils';
import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
import { orderHashUtils } from './order_hash';
+import { OrderValidationUtils } from './order_validation_utils';
import { RemainingFillableCalculator } from './remaining_fillable_calculator';
import { utils } from './utils';
@@ -22,9 +23,16 @@ interface SidedOrderRelevantState {
traderFeeProxyAllowance: BigNumber;
filledTakerAssetAmount: BigNumber;
remainingFillableAssetAmount: BigNumber;
+ isOrderCancelled: boolean;
}
-
-const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001;
+interface OrderValidResult {
+ isValid: true;
+}
+interface OrderInvalidResult {
+ isValid: false;
+ error: ExchangeContractErrs;
+}
+type OrderValidationResult = OrderValidResult | OrderInvalidResult;
export class OrderStateUtils {
private readonly _balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher;
@@ -32,64 +40,56 @@ export class OrderStateUtils {
private static _validateIfOrderIsValid(
signedOrder: SignedOrder,
sidedOrderRelevantState: SidedOrderRelevantState,
- ): void {
+ ): OrderValidationResult {
const isMakerSide = sidedOrderRelevantState.isMakerSide;
+ if (sidedOrderRelevantState.isOrderCancelled) {
+ return { isValid: false, error: ExchangeContractErrs.OrderCancelled };
+ }
const availableTakerAssetAmount = signedOrder.takerAssetAmount.minus(
sidedOrderRelevantState.filledTakerAssetAmount,
);
if (availableTakerAssetAmount.eq(0)) {
- throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
+ return { isValid: false, error: ExchangeContractErrs.OrderRemainingFillAmountZero };
}
if (sidedOrderRelevantState.traderBalance.eq(0)) {
- throw new Error(
- isMakerSide
- ? ExchangeContractErrs.InsufficientMakerBalance
- : ExchangeContractErrs.InsufficientTakerBalance,
- );
+ const error = isMakerSide
+ ? ExchangeContractErrs.InsufficientMakerBalance
+ : ExchangeContractErrs.InsufficientTakerBalance;
+ return { isValid: false, error };
}
if (sidedOrderRelevantState.traderProxyAllowance.eq(0)) {
- throw new Error(
- isMakerSide
- ? ExchangeContractErrs.InsufficientMakerAllowance
- : ExchangeContractErrs.InsufficientTakerAllowance,
- );
+ const error = isMakerSide
+ ? ExchangeContractErrs.InsufficientMakerAllowance
+ : ExchangeContractErrs.InsufficientTakerAllowance;
+ return { isValid: false, error };
}
if (!signedOrder.makerFee.eq(0)) {
if (sidedOrderRelevantState.traderFeeBalance.eq(0)) {
- throw new Error(
- isMakerSide
- ? ExchangeContractErrs.InsufficientMakerFeeBalance
- : ExchangeContractErrs.InsufficientTakerFeeBalance,
- );
+ const error = isMakerSide
+ ? ExchangeContractErrs.InsufficientMakerFeeBalance
+ : ExchangeContractErrs.InsufficientTakerFeeBalance;
+ return { isValid: false, error };
}
if (sidedOrderRelevantState.traderFeeProxyAllowance.eq(0)) {
- throw new Error(
- isMakerSide
- ? ExchangeContractErrs.InsufficientMakerFeeAllowance
- : ExchangeContractErrs.InsufficientTakerFeeAllowance,
- );
+ const error = isMakerSide
+ ? ExchangeContractErrs.InsufficientMakerFeeAllowance
+ : ExchangeContractErrs.InsufficientTakerFeeAllowance;
+ return { isValid: false, error };
}
}
-
- let minFillableTakerAssetAmountWithinNoRoundingErrorRange;
- if (isMakerSide) {
- minFillableTakerAssetAmountWithinNoRoundingErrorRange = signedOrder.takerAssetAmount
- .dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
- .dividedBy(signedOrder.makerAssetAmount);
- } else {
- minFillableTakerAssetAmountWithinNoRoundingErrorRange = signedOrder.makerAssetAmount
- .dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
- .dividedBy(signedOrder.takerAssetAmount);
- }
-
- if (
- sidedOrderRelevantState.remainingFillableAssetAmount.lessThan(
- minFillableTakerAssetAmountWithinNoRoundingErrorRange,
- )
- ) {
- throw new Error(ExchangeContractErrs.OrderFillRoundingError);
+ const remainingTakerAssetAmount = signedOrder.takerAssetAmount.minus(
+ sidedOrderRelevantState.filledTakerAssetAmount,
+ );
+ const isRoundingError = OrderValidationUtils.isRoundingError(
+ remainingTakerAssetAmount,
+ signedOrder.takerAssetAmount,
+ signedOrder.makerAssetAmount,
+ );
+ if (isRoundingError) {
+ return { isValid: false, error: ExchangeContractErrs.OrderFillRoundingError };
}
+ return { isValid: true };
}
constructor(
balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher,
@@ -101,6 +101,7 @@ export class OrderStateUtils {
public async getOpenOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
const orderRelevantState = await this.getOpenOrderRelevantStateAsync(signedOrder);
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
+ const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(orderHash);
const sidedOrderRelevantState = {
isMakerSide: true,
traderBalance: orderRelevantState.makerBalance,
@@ -109,20 +110,21 @@ export class OrderStateUtils {
traderFeeProxyAllowance: orderRelevantState.makerFeeProxyAllowance,
filledTakerAssetAmount: orderRelevantState.filledTakerAssetAmount,
remainingFillableAssetAmount: orderRelevantState.remainingFillableMakerAssetAmount,
+ isOrderCancelled,
};
- try {
- OrderStateUtils._validateIfOrderIsValid(signedOrder, sidedOrderRelevantState);
+ const orderValidationResult = OrderStateUtils._validateIfOrderIsValid(signedOrder, sidedOrderRelevantState);
+ if (orderValidationResult.isValid) {
const orderState: OrderStateValid = {
isValid: true,
orderHash,
orderRelevantState,
};
return orderState;
- } catch (err) {
+ } else {
const orderState: OrderStateInvalid = {
isValid: false,
orderHash,
- error: err.message,
+ error: orderValidationResult.error,
};
return orderState;
}
@@ -278,6 +280,7 @@ export class OrderStateUtils {
traderFeeProxyAllowance,
filledTakerAssetAmount,
remainingFillableAssetAmount,
+ isOrderCancelled,
};
return sidedOrderRelevantState;
}
diff --git a/packages/order-utils/test/order_state_utils_test.ts b/packages/order-utils/test/order_state_utils_test.ts
new file mode 100644
index 000000000..91ef23b69
--- /dev/null
+++ b/packages/order-utils/test/order_state_utils_test.ts
@@ -0,0 +1,124 @@
+import { BigNumber } from '@0xproject/utils';
+import * as chai from 'chai';
+import 'mocha';
+
+import { AbstractBalanceAndProxyAllowanceFetcher } from '../src/abstract/abstract_balance_and_proxy_allowance_fetcher';
+import { AbstractOrderFilledCancelledFetcher } from '../src/abstract/abstract_order_filled_cancelled_fetcher';
+import { OrderStateUtils } from '../src/order_state_utils';
+
+import { chaiSetup } from './utils/chai_setup';
+import { testOrderFactory } from './utils/test_order_factory';
+
+chaiSetup.configure();
+const expect = chai.expect;
+
+describe('OrderStateUtils', () => {
+ describe('#getOpenOrderStateAsync', () => {
+ const buildMockBalanceFetcher = (takerBalance: BigNumber): AbstractBalanceAndProxyAllowanceFetcher => {
+ const balanceFetcher = {
+ async getBalanceAsync(_assetData: string, _userAddress: string): Promise<BigNumber> {
+ return takerBalance;
+ },
+ async getProxyAllowanceAsync(_assetData: string, _userAddress: string): Promise<BigNumber> {
+ return takerBalance;
+ },
+ };
+ return balanceFetcher;
+ };
+ const buildMockOrderFilledFetcher = (
+ filledAmount: BigNumber = new BigNumber(0),
+ cancelled: boolean = false,
+ ): AbstractOrderFilledCancelledFetcher => {
+ const orderFetcher = {
+ async getFilledTakerAmountAsync(_orderHash: string): Promise<BigNumber> {
+ return filledAmount;
+ },
+ async isOrderCancelledAsync(_orderHash: string): Promise<boolean> {
+ return cancelled;
+ },
+ getZRXAssetData(): string {
+ return '';
+ },
+ };
+ return orderFetcher;
+ };
+ it('should have valid order state if order can be fully filled with small maker amount', async () => {
+ const makerAssetAmount = new BigNumber(10);
+ const takerAssetAmount = new BigNumber(10000000000000000);
+ const takerBalance = takerAssetAmount;
+ const orderFilledAmount = new BigNumber(0);
+ const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance);
+ const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount);
+ const [signedOrder] = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount,
+ takerAssetAmount,
+ },
+ 1,
+ );
+
+ const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher);
+ const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder);
+ expect(orderState.isValid).to.eq(true);
+ });
+ it('should be invalid when an order is partially filled where only a rounding error remains', async () => {
+ const makerAssetAmount = new BigNumber(1001);
+ const takerAssetAmount = new BigNumber(3);
+ const takerBalance = takerAssetAmount;
+ const orderFilledAmount = new BigNumber(2);
+ const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance);
+ const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount);
+ const [signedOrder] = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount,
+ takerAssetAmount,
+ },
+ 1,
+ );
+
+ const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher);
+ const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder);
+ expect(orderState.isValid).to.eq(false);
+ });
+ it('should be invalid when an order is cancelled', async () => {
+ const makerAssetAmount = new BigNumber(1000);
+ const takerAssetAmount = new BigNumber(2);
+ const takerBalance = takerAssetAmount;
+ const orderFilledAmount = new BigNumber(0);
+ const isCancelled = true;
+ const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance);
+ const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount, isCancelled);
+ const [signedOrder] = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount,
+ takerAssetAmount,
+ },
+ 1,
+ );
+
+ const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher);
+ const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder);
+ expect(orderState.isValid).to.eq(false);
+ });
+ it('should be invalid when an order is fully filled', async () => {
+ const makerAssetAmount = new BigNumber(1000);
+ const takerAssetAmount = new BigNumber(2);
+ const takerBalance = takerAssetAmount;
+ const orderFilledAmount = takerAssetAmount;
+ const isCancelled = false;
+ const mockBalanceFetcher = buildMockBalanceFetcher(takerBalance);
+ const mockOrderFilledFetcher = buildMockOrderFilledFetcher(orderFilledAmount, isCancelled);
+ const [signedOrder] = testOrderFactory.generateTestSignedOrders(
+ {
+ makerAssetAmount,
+ takerAssetAmount,
+ },
+ 1,
+ );
+
+ const orderStateUtils = new OrderStateUtils(mockBalanceFetcher, mockOrderFilledFetcher);
+ const orderState = await orderStateUtils.getOpenOrderStateAsync(signedOrder);
+ expect(orderState.isValid).to.eq(false);
+ });
+ });
+});
diff --git a/packages/order-watcher/test/order_watcher_test.ts b/packages/order-watcher/test/order_watcher_test.ts
index 00962bed0..38bfde7ef 100644
--- a/packages/order-watcher/test/order_watcher_test.ts
+++ b/packages/order-watcher/test/order_watcher_test.ts
@@ -501,25 +501,27 @@ describe('OrderWatcher', () => {
expect(orderState.isValid).to.be.false();
const invalidOrderState = orderState as OrderStateInvalid;
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError);
+ expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderCancelled);
});
orderWatcher.subscribe(callback);
await contractWrappers.exchange.cancelOrderAsync(signedOrder);
})().catch(done);
});
- it('should emit orderStateInvalid when within rounding error range', (done: DoneCallback) => {
+ it('should emit orderStateInvalid when within rounding error range after a partial fill', (done: DoneCallback) => {
(async () => {
- const remainingFillableAmountInBaseUnits = new BigNumber(100);
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ const fillAmountInBaseUnits = new BigNumber(2);
+ const makerAssetAmount = new BigNumber(1001);
+ const takerAssetAmount = new BigNumber(3);
+ signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
makerAssetData,
takerAssetData,
makerAddress,
takerAddress,
- fillableAmount,
+ makerAssetAmount,
+ takerAssetAmount,
);
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
await orderWatcher.addOrderAsync(signedOrder);
-
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
expect(orderState.isValid).to.be.false();
const invalidOrderState = orderState as OrderStateInvalid;
@@ -527,11 +529,7 @@ describe('OrderWatcher', () => {
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError);
});
orderWatcher.subscribe(callback);
- await contractWrappers.exchange.fillOrderAsync(
- signedOrder,
- fillableAmount.minus(remainingFillableAmountInBaseUnits),
- takerAddress,
- );
+ await contractWrappers.exchange.fillOrderAsync(signedOrder, fillAmountInBaseUnits, takerAddress);
})().catch(done);
});
describe('erc721', () => {
diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts
index fa634420d..04480d093 100644
--- a/packages/types/src/index.ts
+++ b/packages/types/src/index.ts
@@ -62,8 +62,7 @@ export interface ValidatorSignature {
export enum ExchangeContractErrs {
OrderFillExpired = 'ORDER_FILL_EXPIRED',
OrderCancelExpired = 'ORDER_CANCEL_EXPIRED',
- OrderCancelAmountZero = 'ORDER_CANCEL_AMOUNT_ZERO',
- OrderAlreadyCancelledOrFilled = 'ORDER_ALREADY_CANCELLED_OR_FILLED',
+ OrderCancelled = 'ORDER_CANCELLED',
OrderFillAmountZero = 'ORDER_FILL_AMOUNT_ZERO',
OrderRemainingFillAmountZero = 'ORDER_REMAINING_FILL_AMOUNT_ZERO',
OrderFillRoundingError = 'ORDER_FILL_ROUNDING_ERROR',
diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts
index 39bbd404c..32b07473c 100644
--- a/packages/website/ts/utils/utils.ts
+++ b/packages/website/ts/utils/utils.ts
@@ -247,12 +247,9 @@ export const utils = {
} = {
[ExchangeContractErrs.OrderFillExpired]: 'This order has expired',
[ExchangeContractErrs.OrderCancelExpired]: 'This order has expired',
- [ExchangeContractErrs.OrderCancelAmountZero]: "Order cancel amount can't be 0",
- [ExchangeContractErrs.OrderAlreadyCancelledOrFilled]:
- 'This order has already been completely filled or cancelled',
+ [ExchangeContractErrs.OrderCancelled]: 'This order has been cancelled',
[ExchangeContractErrs.OrderFillAmountZero]: "Order fill amount can't be 0",
- [ExchangeContractErrs.OrderRemainingFillAmountZero]:
- 'This order has already been completely filled or cancelled',
+ [ExchangeContractErrs.OrderRemainingFillAmountZero]: 'This order has already been completely filled',
[ExchangeContractErrs.OrderFillRoundingError]:
'Rounding error will occur when filling this order. Please try filling a different amount.',
[ExchangeContractErrs.InsufficientTakerBalance]: