679 lines
31 KiB
TypeScript
679 lines
31 KiB
TypeScript
import { blockchainTests, describe } from '@0x/contracts-test-utils';
|
|
import * as _ from 'lodash';
|
|
|
|
import {
|
|
FillOrderCombinatorialUtils,
|
|
fillOrderCombinatorialUtilsFactoryAsync,
|
|
} from './utils/fill_order_combinatorial_utils';
|
|
import {
|
|
AllowanceAmountScenario,
|
|
AssetDataScenario,
|
|
BalanceAmountScenario,
|
|
ExpirationTimeSecondsScenario,
|
|
FeeAssetDataScenario,
|
|
FeeRecipientAddressScenario,
|
|
OrderAssetAmountScenario,
|
|
TakerAssetFillAmountScenario,
|
|
TakerScenario,
|
|
} from './utils/fill_order_scenarios';
|
|
|
|
const defaultFillScenario = {
|
|
orderScenario: {
|
|
takerScenario: TakerScenario.Unspecified,
|
|
feeRecipientScenario: FeeRecipientAddressScenario.EthUserAddress,
|
|
makerAssetAmountScenario: OrderAssetAmountScenario.Large,
|
|
takerAssetAmountScenario: OrderAssetAmountScenario.Large,
|
|
makerFeeScenario: OrderAssetAmountScenario.Large,
|
|
takerFeeScenario: OrderAssetAmountScenario.Large,
|
|
expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InFuture,
|
|
makerAssetDataScenario: AssetDataScenario.ERC20EighteenDecimals,
|
|
takerAssetDataScenario: AssetDataScenario.ERC20EighteenDecimals,
|
|
makerFeeAssetDataScenario: FeeAssetDataScenario.ERC20EighteenDecimals,
|
|
takerFeeAssetDataScenario: FeeAssetDataScenario.ERC20EighteenDecimals,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.LessThanTakerAssetAmount,
|
|
makerStateScenario: {
|
|
traderAssetBalance: BalanceAmountScenario.Higher,
|
|
traderAssetAllowance: AllowanceAmountScenario.Unlimited,
|
|
feeBalance: BalanceAmountScenario.Higher,
|
|
feeAllowance: AllowanceAmountScenario.Unlimited,
|
|
},
|
|
takerStateScenario: {
|
|
traderAssetBalance: BalanceAmountScenario.Higher,
|
|
traderAssetAllowance: AllowanceAmountScenario.Unlimited,
|
|
feeBalance: BalanceAmountScenario.Higher,
|
|
feeAllowance: AllowanceAmountScenario.Unlimited,
|
|
},
|
|
};
|
|
|
|
blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => {
|
|
let fillOrderCombinatorialUtils: FillOrderCombinatorialUtils;
|
|
|
|
before(async () => {
|
|
fillOrderCombinatorialUtils = await fillOrderCombinatorialUtilsFactoryAsync(web3Wrapper, txDefaults);
|
|
});
|
|
|
|
describe('Fill tests', () => {
|
|
it('should transfer the correct amounts when makerAssetAmount > takerAssetAmount', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
takerAssetAmountScenario: OrderAssetAmountScenario.Small,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
|
|
it('should transfer the correct amounts when makerAssetAmount < takerAssetAmount', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
makerAssetAmountScenario: OrderAssetAmountScenario.Small,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(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.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
|
|
it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
takerScenario: TakerScenario.CorrectlySpecified,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
|
|
it('should transfer the correct amounts maker == feeRecipient', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
feeRecipientScenario: FeeRecipientAddressScenario.MakerAddress,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
|
|
it('should transfer the correct amounts maker == feeRecipient and makerFeeAsset == takerAsset', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
feeRecipientScenario: FeeRecipientAddressScenario.MakerAddress,
|
|
makerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
|
|
it('should transfer the correct amounts taker == feeRecipient', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
feeRecipientScenario: FeeRecipientAddressScenario.TakerAddress,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
|
|
it('should transfer the correct amounts taker == feeRecipient and takerFeeAsset == makerAsset', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
feeRecipientScenario: FeeRecipientAddressScenario.TakerAddress,
|
|
takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
|
|
it('should fill remaining value if takerAssetFillAmount > remaining takerAssetAmount', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanTakerAssetAmount,
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
|
|
it('should revert when taker is specified and order is claimed by other', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
takerScenario: TakerScenario.IncorrectlySpecified,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should revert if makerAssetAmount is 0', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
makerAssetAmountScenario: OrderAssetAmountScenario.Zero,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanTakerAssetAmount,
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should revert if takerAssetAmount is 0', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
takerAssetAmountScenario: OrderAssetAmountScenario.Zero,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.GreaterThanTakerAssetAmount,
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should revert if an order is expired', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
expirationTimeSecondsScenario: ExpirationTimeSecondsScenario.InPast,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
});
|
|
|
|
describe('ERC20', () => {
|
|
const assetCombinations = getAllPossiblePairs([
|
|
AssetDataScenario.ERC20ZeroDecimals,
|
|
AssetDataScenario.ERC20FiveDecimals,
|
|
AssetDataScenario.ERC20EighteenDecimals,
|
|
]);
|
|
for (const [makerAsset, takerAsset] of assetCombinations) {
|
|
it(`should transfer correct amounts between ${makerAsset} and ${takerAsset}`, async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
makerAssetDataScenario: makerAsset,
|
|
takerAssetDataScenario: takerAsset,
|
|
},
|
|
};
|
|
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 not be able to pay maker fee with maker asset if none is left over (double-spend)', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
makerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
makerStateScenario: {
|
|
...defaultFillScenario.makerStateScenario,
|
|
traderAssetBalance: BalanceAmountScenario.Exact,
|
|
feeBalance: BalanceAmountScenario.Zero,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should not be able to pay taker fee with taker asset if none is left over (double-spend)', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
takerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
takerStateScenario: {
|
|
...defaultFillScenario.takerStateScenario,
|
|
traderAssetBalance: BalanceAmountScenario.Exact,
|
|
feeBalance: BalanceAmountScenario.Zero,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(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 revert if maker balance is too low to fill order', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
makerStateScenario: {
|
|
...defaultFillScenario.makerStateScenario,
|
|
traderAssetBalance: BalanceAmountScenario.TooLow,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should revert if taker balance is too low to fill order', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
takerStateScenario: {
|
|
...defaultFillScenario.makerStateScenario,
|
|
traderAssetBalance: BalanceAmountScenario.TooLow,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should revert if maker allowances are too low to fill order', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
makerStateScenario: {
|
|
...defaultFillScenario.makerStateScenario,
|
|
traderAssetAllowance: AllowanceAmountScenario.TooLow,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should revert if taker allowances are too low to fill order', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
takerStateScenario: {
|
|
...defaultFillScenario.makerStateScenario,
|
|
traderAssetAllowance: AllowanceAmountScenario.TooLow,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should revert if maker fee balance is too low to fill order', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
makerStateScenario: {
|
|
...defaultFillScenario.makerStateScenario,
|
|
feeBalance: BalanceAmountScenario.TooLow,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should revert if taker fee balance is too low to fill order', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
takerStateScenario: {
|
|
...defaultFillScenario.makerStateScenario,
|
|
feeBalance: BalanceAmountScenario.TooLow,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should revert 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 revert if taker fee allowances are too low to fill order', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
takerStateScenario: {
|
|
...defaultFillScenario.makerStateScenario,
|
|
feeAllowance: AllowanceAmountScenario.TooLow,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
});
|
|
|
|
describe('ERC721', () => {
|
|
it('should be able to pay maker fee with taker ERC721', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
takerAssetDataScenario: AssetDataScenario.ERC721,
|
|
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 ERC721', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
makerAssetDataScenario: AssetDataScenario.ERC721,
|
|
takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
takerStateScenario: {
|
|
...defaultFillScenario.takerStateScenario,
|
|
feeBalance: BalanceAmountScenario.Zero,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
|
|
it('should not be able to pay maker fee with maker ERC721 (double-spend)', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
makerAssetDataScenario: AssetDataScenario.ERC721,
|
|
makerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
makerStateScenario: {
|
|
...defaultFillScenario.makerStateScenario,
|
|
feeBalance: BalanceAmountScenario.Zero,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should be able to pay taker fee with taker ERC721 (double-spend)', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
takerAssetDataScenario: AssetDataScenario.ERC721,
|
|
takerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
takerStateScenario: {
|
|
...defaultFillScenario.takerStateScenario,
|
|
feeBalance: BalanceAmountScenario.Zero,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
});
|
|
|
|
describe('ERC1155', () => {
|
|
const assetTypes = [AssetDataScenario.ERC1155Fungible, AssetDataScenario.ERC1155NonFungible];
|
|
for (const assetType of assetTypes) {
|
|
describe(_.startCase(_.toLower((/ERC1155(.+)/.exec(assetType) as string[])[1])), () => {
|
|
it('should be able to pay maker fee with taker asset', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
takerAssetDataScenario: assetType,
|
|
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,
|
|
makerAssetDataScenario: assetType,
|
|
takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
takerStateScenario: {
|
|
...defaultFillScenario.takerStateScenario,
|
|
feeBalance: BalanceAmountScenario.Zero,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
|
|
it('should not be able to pay maker fee with maker asset if not enough left (double-spend)', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
makerAssetDataScenario: assetType,
|
|
makerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
makerStateScenario: {
|
|
...defaultFillScenario.makerStateScenario,
|
|
traderAssetBalance: BalanceAmountScenario.Exact,
|
|
feeBalance: BalanceAmountScenario.Zero,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should be able to pay taker fee with taker asset if not enough left (double-spend)', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
takerAssetDataScenario: assetType,
|
|
takerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
takerStateScenario: {
|
|
...defaultFillScenario.takerStateScenario,
|
|
traderAssetBalance: BalanceAmountScenario.Exact,
|
|
feeBalance: BalanceAmountScenario.Zero,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
describe('MultiAssetProxy', () => {
|
|
it('should be able to pay maker fee with taker MAP', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
takerAssetDataScenario: AssetDataScenario.MultiAssetERC20,
|
|
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 MAP', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
makerAssetDataScenario: AssetDataScenario.MultiAssetERC20,
|
|
takerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
takerStateScenario: {
|
|
...defaultFillScenario.takerStateScenario,
|
|
feeBalance: BalanceAmountScenario.Zero,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
|
|
it('should not be able to pay maker fee with maker MAP (double-spend)', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
makerAssetDataScenario: AssetDataScenario.MultiAssetERC20,
|
|
makerFeeAssetDataScenario: FeeAssetDataScenario.MakerToken,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
makerStateScenario: {
|
|
...defaultFillScenario.makerStateScenario,
|
|
feeBalance: BalanceAmountScenario.Zero,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
|
|
it('should be able to pay taker fee with taker MAP (double-spend)', async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
takerAssetDataScenario: AssetDataScenario.MultiAssetERC20,
|
|
takerFeeAssetDataScenario: FeeAssetDataScenario.TakerToken,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
takerStateScenario: {
|
|
...defaultFillScenario.takerStateScenario,
|
|
feeBalance: BalanceAmountScenario.Zero,
|
|
},
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioFailureAsync(fillScenario);
|
|
});
|
|
});
|
|
|
|
describe('Maker/taker asset combinations', () => {
|
|
const assetDataScenarios = [
|
|
AssetDataScenario.ERC20EighteenDecimals,
|
|
AssetDataScenario.ERC721,
|
|
AssetDataScenario.ERC1155Fungible,
|
|
AssetDataScenario.ERC1155NonFungible,
|
|
AssetDataScenario.MultiAssetERC20,
|
|
];
|
|
for (const [makerAsset, takerAsset] of getAllPossiblePairs(assetDataScenarios)) {
|
|
it(`should successfully exchange ${makerAsset} for ${takerAsset}`, async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
makerAssetDataScenario: makerAsset,
|
|
takerAssetDataScenario: takerAsset,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
}
|
|
});
|
|
|
|
describe('Maker/taker fee asset combinations', () => {
|
|
const feeAssetPairs = getAllPossiblePairs([
|
|
FeeAssetDataScenario.ERC20EighteenDecimals,
|
|
FeeAssetDataScenario.ERC721,
|
|
FeeAssetDataScenario.ERC1155Fungible,
|
|
FeeAssetDataScenario.ERC1155NonFungible,
|
|
FeeAssetDataScenario.MultiAssetERC20,
|
|
]);
|
|
for (const [makerFeeAsset, takerFeeAsset] of feeAssetPairs) {
|
|
it(`should successfully pay maker fee ${makerFeeAsset} and taker fee ${takerFeeAsset}`, async () => {
|
|
const fillScenario = {
|
|
...defaultFillScenario,
|
|
orderScenario: {
|
|
...defaultFillScenario.orderScenario,
|
|
makerFeeAssetDataScenario: makerFeeAsset,
|
|
takerFeeAssetDataScenario: takerFeeAsset,
|
|
},
|
|
takerAssetFillAmountScenario: TakerAssetFillAmountScenario.ExactlyTakerAssetAmount,
|
|
};
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioSuccessAsync(fillScenario);
|
|
});
|
|
}
|
|
});
|
|
|
|
describe.optional('Combinatorially generated fills orders', () => {
|
|
const allFillScenarios = FillOrderCombinatorialUtils.generateFillOrderCombinations();
|
|
for (const fillScenario of allFillScenarios) {
|
|
const description = `Combinatorial OrderFill: ${JSON.stringify(fillScenario)}`;
|
|
it(description, async () => {
|
|
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(fillScenario);
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
function getAllPossiblePairs<T>(choices: T[]): Array<[T, T]> {
|
|
const pairs: Array<[T, T]> = [];
|
|
for (const i of _.times(choices.length)) {
|
|
for (const j of _.times(choices.length)) {
|
|
pairs.push([choices[i], choices[j]]);
|
|
}
|
|
}
|
|
return pairs;
|
|
}
|
|
// tslint:disable: max-file-line-count
|