@0x/contracts-exchange
: Major rework of fill_order_combinatorial_utils
.
`@0x/contracts-exchange`: Add more arbitrary fee token tests. `@0x/contracts-exchange`: Fix broken tests.
This commit is contained in:
committed by
Amir Bandeali
parent
76d577a08d
commit
aebb923c2d
@@ -362,6 +362,17 @@ describe('Exchange core', () => {
|
||||
(transferLogs[1] as LogWithDecodedArgs<DummyERC20TokenTransferEventArgs>).args._value,
|
||||
).to.be.bignumber.equal(signedOrder.takerFee);
|
||||
});
|
||||
|
||||
it('should throw if order is expired', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
signedOrder = await orderFactory.newSignedOrderAsync({
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
|
||||
});
|
||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedError = new ExchangeRevertErrors.OrderStatusError(orderHash, OrderStatus.Expired);
|
||||
const tx = exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Testing exchange of ERC20 tokens with no return values', () => {
|
||||
|
@@ -8,7 +8,6 @@ import {
|
||||
FeeRecipientAddressScenario,
|
||||
FillScenario,
|
||||
OrderAssetAmountScenario,
|
||||
provider,
|
||||
TakerAssetFillAmountScenario,
|
||||
TakerScenario,
|
||||
txDefaults,
|
||||
@@ -39,15 +38,15 @@ const defaultFillScenario = {
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.LessThanRemainingFillableTakerAssetAmount,
|
||||
makerStateScenario: {
|
||||
traderAssetBalance: BalanceAmountScenario.Higher,
|
||||
traderAssetAllowance: AllowanceAmountScenario.Higher,
|
||||
traderAssetAllowance: AllowanceAmountScenario.Unlimited,
|
||||
feeBalance: BalanceAmountScenario.Higher,
|
||||
feeAllowance: AllowanceAmountScenario.Higher,
|
||||
feeAllowance: AllowanceAmountScenario.Unlimited,
|
||||
},
|
||||
takerStateScenario: {
|
||||
traderAssetBalance: BalanceAmountScenario.Higher,
|
||||
traderAssetAllowance: AllowanceAmountScenario.Higher,
|
||||
traderAssetAllowance: AllowanceAmountScenario.Unlimited,
|
||||
feeBalance: BalanceAmountScenario.Higher,
|
||||
feeAllowance: AllowanceAmountScenario.Higher,
|
||||
feeAllowance: AllowanceAmountScenario.Unlimited,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -72,7 +71,7 @@ describe('FillOrder Tests', () => {
|
||||
_.forEach(fillScenarios, fillScenario => {
|
||||
const description = `Combinatorial OrderFill: ${JSON.stringify(fillScenario)}`;
|
||||
it(description, async () => {
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(fillScenario);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -84,8 +83,9 @@ describe('FillOrder Tests', () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
@@ -94,8 +94,9 @@ describe('FillOrder Tests', () => {
|
||||
takerAssetAmountScenario: OrderAssetAmountScenario.Small,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
@@ -104,8 +105,9 @@ describe('FillOrder Tests', () => {
|
||||
makerAssetAmountScenario: OrderAssetAmountScenario.Small,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount with zero decimals', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
@@ -115,8 +117,9 @@ describe('FillOrder Tests', () => {
|
||||
makerAssetDataScenario: AssetDataScenario.ERC20ZeroDecimals,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
@@ -125,15 +128,49 @@ describe('FillOrder Tests', () => {
|
||||
takerScenario: TakerScenario.CorrectlySpecified,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should fill remaining value if takerAssetFillAmount > remaining takerAssetAmount', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should be able to pay maker fee with taker asset', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
orderScenario: {
|
||||
...defaultFillScenario.orderScenario,
|
||||
makerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken,
|
||||
},
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
||||
makerStateScenario: {
|
||||
...defaultFillScenario.makerStateScenario,
|
||||
feeBalance: BalanceAmountScenario.Zero,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should be able to pay taker fee with maker asset', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
orderScenario: {
|
||||
...defaultFillScenario.orderScenario,
|
||||
takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken,
|
||||
},
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
||||
takerStateScenario: {
|
||||
...defaultFillScenario.takerStateScenario,
|
||||
feeBalance: BalanceAmountScenario.Zero,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw when taker is specified and order is claimed by other', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
@@ -142,7 +179,7 @@ describe('FillOrder Tests', () => {
|
||||
takerScenario: TakerScenario.IncorrectlySpecified,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if makerAssetAmount is 0', async () => {
|
||||
@@ -154,7 +191,7 @@ describe('FillOrder Tests', () => {
|
||||
},
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if takerAssetAmount is 0', async () => {
|
||||
@@ -166,7 +203,7 @@ describe('FillOrder Tests', () => {
|
||||
},
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanRemainingFillableTakerAssetAmount,
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if takerAssetFillAmount is 0', async () => {
|
||||
@@ -174,7 +211,7 @@ describe('FillOrder Tests', () => {
|
||||
...defaultFillScenario,
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.Zero,
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if an order is expired', async () => {
|
||||
@@ -185,7 +222,7 @@ describe('FillOrder Tests', () => {
|
||||
expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InPast,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if maker erc20Balances are too low to fill order', async () => {
|
||||
@@ -196,7 +233,7 @@ describe('FillOrder Tests', () => {
|
||||
traderAssetBalance: BalanceAmountScenario.TooLow,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if taker erc20Balances are too low to fill order', async () => {
|
||||
@@ -207,7 +244,7 @@ describe('FillOrder Tests', () => {
|
||||
traderAssetBalance: BalanceAmountScenario.TooLow,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if maker allowances are too low to fill order', async () => {
|
||||
@@ -218,7 +255,7 @@ describe('FillOrder Tests', () => {
|
||||
traderAssetAllowance: AllowanceAmountScenario.TooLow,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if taker allowances are too low to fill order', async () => {
|
||||
@@ -229,7 +266,51 @@ describe('FillOrder Tests', () => {
|
||||
traderAssetAllowance: AllowanceAmountScenario.TooLow,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if maker fee erc20Balances are too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
makerStateScenario: {
|
||||
...defaultFillScenario.makerStateScenario,
|
||||
feeBalance: BalanceAmountScenario.TooLow,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if taker fee erc20Balances are too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
takerStateScenario: {
|
||||
...defaultFillScenario.makerStateScenario,
|
||||
feeBalance: BalanceAmountScenario.TooLow,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if maker fee allowances are too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
makerStateScenario: {
|
||||
...defaultFillScenario.makerStateScenario,
|
||||
feeAllowance: AllowanceAmountScenario.TooLow,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should throw if taker fee allowances are too low to fill order', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
takerStateScenario: {
|
||||
...defaultFillScenario.makerStateScenario,
|
||||
feeAllowance: AllowanceAmountScenario.TooLow,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -244,7 +325,7 @@ describe('FillOrder Tests', () => {
|
||||
},
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should successfully fill order when makerAsset is ERC721 and takerAsset is ERC20', async () => {
|
||||
@@ -257,7 +338,7 @@ describe('FillOrder Tests', () => {
|
||||
},
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario, true);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should successfully fill order when makerAsset is ERC20 and takerAsset is ERC721', async () => {
|
||||
@@ -270,7 +351,7 @@ describe('FillOrder Tests', () => {
|
||||
},
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyRemainingFillableTakerAssetAmount,
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should successfully fill order when makerAsset is ERC721 and approveAll is set for it', async () => {
|
||||
@@ -287,7 +368,7 @@ describe('FillOrder Tests', () => {
|
||||
traderAssetAllowance: AllowanceAmountScenario.Unlimited,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should successfully fill order when makerAsset and takerAsset are ERC721 and approveAll is set for them', async () => {
|
||||
@@ -308,7 +389,43 @@ describe('FillOrder Tests', () => {
|
||||
traderAssetAllowance: AllowanceAmountScenario.Unlimited,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should be able to pay maker fee with taker asset', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
orderScenario: {
|
||||
...defaultFillScenario.orderScenario,
|
||||
takerAssetDataScenario: AssetDataScenario.ERC721,
|
||||
makerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken,
|
||||
},
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
||||
makerStateScenario: {
|
||||
...defaultFillScenario.makerStateScenario,
|
||||
feeBalance: BalanceAmountScenario.Zero,
|
||||
feeAllowance: AllowanceAmountScenario.Unlimited,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
|
||||
it('should be able to pay taker fee with maker asset', async () => {
|
||||
const fillScenario = {
|
||||
...defaultFillScenario,
|
||||
orderScenario: {
|
||||
...defaultFillScenario.orderScenario,
|
||||
makerAssetDataScenario: AssetDataScenario.ERC721,
|
||||
takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken,
|
||||
},
|
||||
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
||||
takerStateScenario: {
|
||||
...defaultFillScenario.takerStateScenario,
|
||||
feeBalance: BalanceAmountScenario.Zero,
|
||||
feeAllowance: AllowanceAmountScenario.Unlimited,
|
||||
},
|
||||
};
|
||||
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -3,7 +3,6 @@ import {
|
||||
chaiSetup,
|
||||
constants,
|
||||
FillResults,
|
||||
getRevertReasonOrErrorMessageForSendTransactionAsync,
|
||||
provider,
|
||||
testCombinatoriallyWithReferenceFuncAsync,
|
||||
txDefaults,
|
||||
@@ -12,7 +11,7 @@ import {
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { Order, RevertReason, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, providerUtils } from '@0x/utils';
|
||||
import { BigNumber, providerUtils, StringRevertError } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -77,9 +76,7 @@ describe('Exchange core internal functions', () => {
|
||||
txDefaults,
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
overflowErrorForSendTransaction = new Error(
|
||||
await getRevertReasonOrErrorMessageForSendTransactionAsync(RevertReason.Uint256Overflow),
|
||||
);
|
||||
overflowErrorForSendTransaction = new Error(RevertReason.Uint256Overflow);
|
||||
divisionByZeroErrorForCall = new Error(RevertReason.DivisionByZero);
|
||||
roundingErrorForCall = new Error(RevertReason.RoundingError);
|
||||
});
|
||||
@@ -160,6 +157,21 @@ describe('Exchange core internal functions', () => {
|
||||
return product.dividedToIntegerBy(denominator);
|
||||
}
|
||||
|
||||
function wrapCallTestFunction<T>(
|
||||
callAsync: (...args: any[]) => Promise<T>,
|
||||
): (...args: any[]) => Promise<T> {
|
||||
return async (...args: any[]): Promise<T> => {
|
||||
try {
|
||||
return await callAsync(...args);
|
||||
} catch (err) {
|
||||
if (err instanceof StringRevertError) {
|
||||
throw new Error(err.values.message as string);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe('addFillResults', async () => {
|
||||
function makeFillResults(value: BigNumber): FillResults {
|
||||
return {
|
||||
@@ -203,7 +215,7 @@ describe('Exchange core internal functions', () => {
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'addFillResults',
|
||||
referenceAddFillResultsAsync,
|
||||
testAddFillResultsAsync,
|
||||
wrapCallTestFunction(testAddFillResultsAsync),
|
||||
[uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
@@ -267,7 +279,7 @@ describe('Exchange core internal functions', () => {
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'calculateFillResults',
|
||||
referenceCalculateFillResultsAsync,
|
||||
testCalculateFillResultsAsync,
|
||||
wrapCallTestFunction(testCalculateFillResultsAsync),
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
@@ -297,7 +309,7 @@ describe('Exchange core internal functions', () => {
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'getPartialAmountFloor',
|
||||
referenceGetPartialAmountFloorAsync,
|
||||
testGetPartialAmountFloorAsync,
|
||||
wrapCallTestFunction(testGetPartialAmountFloorAsync),
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
@@ -334,7 +346,7 @@ describe('Exchange core internal functions', () => {
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'getPartialAmountCeil',
|
||||
referenceGetPartialAmountCeilAsync,
|
||||
testGetPartialAmountCeilAsync,
|
||||
wrapCallTestFunction(testGetPartialAmountCeilAsync),
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
@@ -350,7 +362,7 @@ describe('Exchange core internal functions', () => {
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'safeGetPartialAmountFloor',
|
||||
referenceSafeGetPartialAmountFloorAsync,
|
||||
testSafeGetPartialAmountFloorAsync,
|
||||
wrapCallTestFunction(testSafeGetPartialAmountFloorAsync),
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
@@ -391,7 +403,7 @@ describe('Exchange core internal functions', () => {
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'safeGetPartialAmountCeil',
|
||||
referenceSafeGetPartialAmountCeilAsync,
|
||||
testSafeGetPartialAmountCeilAsync,
|
||||
wrapCallTestFunction(testSafeGetPartialAmountCeilAsync),
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
@@ -407,7 +419,7 @@ describe('Exchange core internal functions', () => {
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'isRoundingErrorFloor',
|
||||
referenceIsRoundingErrorFloorAsync,
|
||||
testIsRoundingErrorFloorAsync,
|
||||
wrapCallTestFunction(testIsRoundingErrorFloorAsync),
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
@@ -423,7 +435,7 @@ describe('Exchange core internal functions', () => {
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'isRoundingErrorCeil',
|
||||
referenceIsRoundingErrorCeilAsync,
|
||||
testIsRoundingErrorCeilAsync,
|
||||
wrapCallTestFunction(testIsRoundingErrorCeilAsync),
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
@@ -475,7 +487,7 @@ describe('Exchange core internal functions', () => {
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'updateFilledState',
|
||||
referenceUpdateFilledStateAsync,
|
||||
testUpdateFilledStateAsync,
|
||||
wrapCallTestFunction(testUpdateFilledStateAsync),
|
||||
[uint256Values, uint256Values, bytes32Values],
|
||||
);
|
||||
});
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -184,18 +184,10 @@ export class AssetWrapper {
|
||||
);
|
||||
if (!isProxyApprovedForAll && desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
const isApproved = true;
|
||||
await erc721Wrapper.approveProxyForAllAsync(
|
||||
assetProxyData.tokenAddress,
|
||||
assetProxyData.tokenId,
|
||||
isApproved,
|
||||
);
|
||||
await erc721Wrapper.approveProxyForAllAsync(assetProxyData.tokenAddress, userAddress, isApproved);
|
||||
} else if (isProxyApprovedForAll && desiredAllowance.eq(0)) {
|
||||
const isApproved = false;
|
||||
await erc721Wrapper.approveProxyForAllAsync(
|
||||
assetProxyData.tokenAddress,
|
||||
assetProxyData.tokenId,
|
||||
isApproved,
|
||||
);
|
||||
await erc721Wrapper.approveProxyForAllAsync(assetProxyData.tokenAddress, userAddress, isApproved);
|
||||
} else if (isProxyApprovedForAll && desiredAllowance.eq(constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
return; // Noop
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
163
contracts/exchange/test/utils/fill_order_simulator.ts
Normal file
163
contracts/exchange/test/utils/fill_order_simulator.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import { constants, FillResults, orderUtils } from '@0x/contracts-test-utils';
|
||||
import {
|
||||
AbstractBalanceAndProxyAllowanceLazyStore as LazyStore,
|
||||
ExchangeTransferSimulator,
|
||||
Order,
|
||||
TradeSide,
|
||||
TransferType,
|
||||
} from '@0x/order-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
export enum FillOrderError {
|
||||
OrderUnfillable = 'ORDER_UNFILLABLE',
|
||||
InvalidSender = 'INVALID_SENDER',
|
||||
InvalidTakerAmount = 'INVALID_TAKER_AMOUNT',
|
||||
InvalidMakerAmount = 'INVALID_MAKER_AMOUNT',
|
||||
InvalidTaker = 'INVALID_TAKER',
|
||||
InvalidFillPrice = 'INVALID_FILL_PRICE',
|
||||
TransferFailed = 'TRANSFER_FAILED',
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified fill order simulator.
|
||||
*/
|
||||
export class FillOrderSimulator {
|
||||
public readonly lazyStore: LazyStore;
|
||||
private readonly _transferSimulator: ExchangeTransferSimulator;
|
||||
|
||||
constructor(lazyStore: LazyStore) {
|
||||
this.lazyStore = lazyStore;
|
||||
this._transferSimulator = new ExchangeTransferSimulator(lazyStore);
|
||||
}
|
||||
|
||||
public async simulateFillOrderAsync(
|
||||
order: Order,
|
||||
takerAddress: string,
|
||||
takerAssetFillAmount: BigNumber,
|
||||
takerAssetFilledAmount: BigNumber = constants.ZERO_AMOUNT,
|
||||
): Promise<FillResults> {
|
||||
const remainingTakerAssetAmount = order.takerAssetAmount.minus(takerAssetFilledAmount);
|
||||
const makerAssetFilledAmount = orderUtils.getPartialAmountFloor(
|
||||
takerAssetFilledAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
);
|
||||
|
||||
validateFill(
|
||||
order,
|
||||
takerAddress,
|
||||
takerAssetFillAmount,
|
||||
makerAssetFilledAmount,
|
||||
takerAssetFilledAmount,
|
||||
remainingTakerAssetAmount,
|
||||
);
|
||||
|
||||
const finalTakerAssetFillAmount = BigNumber.min(takerAssetFillAmount, remainingTakerAssetAmount);
|
||||
const makerAssetFillAmount = orderUtils.getPartialAmountFloor(
|
||||
finalTakerAssetFillAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
);
|
||||
const makerFeePaid = orderUtils.getPartialAmountFloor(
|
||||
makerAssetFillAmount,
|
||||
order.makerAssetAmount,
|
||||
order.makerFee,
|
||||
);
|
||||
const takerFeePaid = orderUtils.getPartialAmountFloor(
|
||||
finalTakerAssetFillAmount,
|
||||
order.takerAssetAmount,
|
||||
order.takerFee,
|
||||
);
|
||||
|
||||
try {
|
||||
// Maker -> Taker
|
||||
await this._transferSimulator.transferFromAsync(
|
||||
order.makerAssetData,
|
||||
order.makerAddress,
|
||||
takerAddress,
|
||||
makerAssetFillAmount,
|
||||
TradeSide.Maker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
// Taker -> Maker
|
||||
await this._transferSimulator.transferFromAsync(
|
||||
order.takerAssetData,
|
||||
takerAddress,
|
||||
order.makerAddress,
|
||||
finalTakerAssetFillAmount,
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
// Maker fee -> fee recipient
|
||||
if (makerFeePaid.isGreaterThan(0)) {
|
||||
await this._transferSimulator.transferFromAsync(
|
||||
order.makerFeeAssetData,
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
makerFeePaid,
|
||||
TradeSide.Maker,
|
||||
TransferType.Fee,
|
||||
);
|
||||
}
|
||||
// Taker fee -> fee recipient
|
||||
if (takerFeePaid.isGreaterThan(0)) {
|
||||
await this._transferSimulator.transferFromAsync(
|
||||
order.takerFeeAssetData,
|
||||
takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
takerFeePaid,
|
||||
TradeSide.Taker,
|
||||
TransferType.Fee,
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(FillOrderError.TransferFailed);
|
||||
}
|
||||
|
||||
return {
|
||||
takerAssetFilledAmount: finalTakerAssetFillAmount,
|
||||
makerAssetFilledAmount: makerAssetFillAmount,
|
||||
makerFeePaid,
|
||||
takerFeePaid,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function validateFill(
|
||||
order: Order,
|
||||
takerAddress: string,
|
||||
takerAssetFillAmount: BigNumber,
|
||||
makerAssetFilledAmount: BigNumber,
|
||||
takerAssetFilledAmount: BigNumber,
|
||||
remainingTakerAssetAmount: BigNumber,
|
||||
): void {
|
||||
const now = Math.floor(_.now() / 1000);
|
||||
if (remainingTakerAssetAmount.isEqualTo(0) || order.expirationTimeSeconds.isLessThanOrEqualTo(now)) {
|
||||
throw new Error(FillOrderError.OrderUnfillable);
|
||||
}
|
||||
|
||||
if (order.senderAddress !== constants.NULL_ADDRESS && order.senderAddress !== takerAddress) {
|
||||
throw new Error(FillOrderError.InvalidSender);
|
||||
}
|
||||
|
||||
if (order.takerAddress !== constants.NULL_ADDRESS && order.takerAddress !== takerAddress) {
|
||||
throw new Error(FillOrderError.InvalidTaker);
|
||||
}
|
||||
|
||||
if (order.makerAssetAmount.isEqualTo(0)) {
|
||||
throw new Error(FillOrderError.InvalidMakerAmount);
|
||||
}
|
||||
|
||||
if (takerAssetFillAmount.isEqualTo(0)) {
|
||||
throw new Error(FillOrderError.InvalidTakerAmount);
|
||||
}
|
||||
|
||||
if (
|
||||
makerAssetFilledAmount
|
||||
.times(order.takerAssetAmount)
|
||||
.isGreaterThan(takerAssetFilledAmount.times(order.makerAssetAmount))
|
||||
) {
|
||||
throw new Error(FillOrderError.InvalidFillPrice);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user