Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/connect/sra-api-v2
This commit is contained in:
commit
89174cd63f
@ -81,7 +81,7 @@
|
|||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"chai-bignumber": "^2.0.1",
|
"chai-bignumber": "^2.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
"@types/tmp": "^0.0.33",
|
"@types/tmp": "^0.0.33",
|
||||||
"@types/yargs": "^10.0.0",
|
"@types/yargs": "^10.0.0",
|
||||||
"chai": "^4.1.2",
|
"chai": "^4.1.2",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^5.2.0",
|
"mocha": "^5.2.0",
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"@types/valid-url": "^1.0.2",
|
"@types/valid-url": "^1.0.2",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^4.1.0",
|
"mocha": "^4.1.0",
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
"@0xproject/tslint-config": "^1.0.5",
|
"@0xproject/tslint-config": "^1.0.5",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^4.1.0",
|
"mocha": "^4.1.0",
|
||||||
"npm-run-all": "^4.1.2",
|
"npm-run-all": "^4.1.2",
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/monorepo-scripts": "^1.0.5",
|
"@0xproject/monorepo-scripts": "^1.0.5",
|
||||||
"@0xproject/tslint-config": "^1.0.5",
|
"@0xproject/tslint-config": "^1.0.5",
|
||||||
"@types/fetch-mock": "^5.12.2",
|
"@types/fetch-mock": "^6.0.3",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"@types/query-string": "^5.0.1",
|
"@types/query-string": "^5.0.1",
|
||||||
@ -73,7 +73,7 @@
|
|||||||
"async-child-process": "^1.1.1",
|
"async-child-process": "^1.1.1",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"fetch-mock": "^5.13.1",
|
"fetch-mock": "^5.13.1",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"chai-bignumber": "^2.0.1",
|
"chai-bignumber": "^2.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^4.1.0",
|
"mocha": "^4.1.0",
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"chai-bignumber": "^2.0.1",
|
"chai-bignumber": "^2.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^4.1.0",
|
"mocha": "^4.1.0",
|
||||||
|
@ -104,6 +104,17 @@ describe('FillOrder Tests', () => {
|
|||||||
};
|
};
|
||||||
await fillOrderCombinatorialUtils.testFillOrderScenarioAsync(provider, fillScenario);
|
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 () => {
|
it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => {
|
||||||
const fillScenario = {
|
const fillScenario = {
|
||||||
...defaultFillScenario,
|
...defaultFillScenario,
|
||||||
|
@ -81,6 +81,12 @@ export async function fillOrderCombinatorialUtilsFactoryAsync(
|
|||||||
erc20FiveDecimalTokenCount,
|
erc20FiveDecimalTokenCount,
|
||||||
fiveDecimals,
|
fiveDecimals,
|
||||||
);
|
);
|
||||||
|
const zeroDecimals = new BigNumber(0);
|
||||||
|
const erc20ZeroDecimalTokenCount = 2;
|
||||||
|
const [erc20ZeroDecimalTokenA, erc20ZeroDecimalTokenB] = await erc20Wrapper.deployDummyTokensAsync(
|
||||||
|
erc20ZeroDecimalTokenCount,
|
||||||
|
zeroDecimals,
|
||||||
|
);
|
||||||
const erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
const erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
||||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||||
|
|
||||||
@ -119,6 +125,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync(
|
|||||||
zrxToken.address,
|
zrxToken.address,
|
||||||
[erc20EighteenDecimalTokenA.address, erc20EighteenDecimalTokenB.address],
|
[erc20EighteenDecimalTokenA.address, erc20EighteenDecimalTokenB.address],
|
||||||
[erc20FiveDecimalTokenA.address, erc20FiveDecimalTokenB.address],
|
[erc20FiveDecimalTokenA.address, erc20FiveDecimalTokenB.address],
|
||||||
|
[erc20ZeroDecimalTokenA.address, erc20ZeroDecimalTokenB.address],
|
||||||
erc721Token,
|
erc721Token,
|
||||||
erc721Balances,
|
erc721Balances,
|
||||||
exchangeContract.address,
|
exchangeContract.address,
|
||||||
|
@ -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 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 TEN_UNITS_FIVE_DECIMALS = new BigNumber(1_000_000);
|
||||||
const FIVE_UNITS_FIVE_DECIMALS = new BigNumber(500_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);
|
const ONE_NFT_UNIT = new BigNumber(1);
|
||||||
|
|
||||||
export class OrderFactoryFromScenario {
|
export class OrderFactoryFromScenario {
|
||||||
@ -28,6 +30,7 @@ export class OrderFactoryFromScenario {
|
|||||||
private readonly _zrxAddress: string;
|
private readonly _zrxAddress: string;
|
||||||
private readonly _nonZrxERC20EighteenDecimalTokenAddresses: string[];
|
private readonly _nonZrxERC20EighteenDecimalTokenAddresses: string[];
|
||||||
private readonly _erc20FiveDecimalTokenAddresses: string[];
|
private readonly _erc20FiveDecimalTokenAddresses: string[];
|
||||||
|
private readonly _erc20ZeroDecimalTokenAddresses: string[];
|
||||||
private readonly _erc721Token: DummyERC721TokenContract;
|
private readonly _erc721Token: DummyERC721TokenContract;
|
||||||
private readonly _erc721Balances: ERC721TokenIdsByOwner;
|
private readonly _erc721Balances: ERC721TokenIdsByOwner;
|
||||||
private readonly _exchangeAddress: string;
|
private readonly _exchangeAddress: string;
|
||||||
@ -36,6 +39,7 @@ export class OrderFactoryFromScenario {
|
|||||||
zrxAddress: string,
|
zrxAddress: string,
|
||||||
nonZrxERC20EighteenDecimalTokenAddresses: string[],
|
nonZrxERC20EighteenDecimalTokenAddresses: string[],
|
||||||
erc20FiveDecimalTokenAddresses: string[],
|
erc20FiveDecimalTokenAddresses: string[],
|
||||||
|
erc20ZeroDecimalTokenAddresses: string[],
|
||||||
erc721Token: DummyERC721TokenContract,
|
erc721Token: DummyERC721TokenContract,
|
||||||
erc721Balances: ERC721TokenIdsByOwner,
|
erc721Balances: ERC721TokenIdsByOwner,
|
||||||
exchangeAddress: string,
|
exchangeAddress: string,
|
||||||
@ -44,6 +48,7 @@ export class OrderFactoryFromScenario {
|
|||||||
this._zrxAddress = zrxAddress;
|
this._zrxAddress = zrxAddress;
|
||||||
this._nonZrxERC20EighteenDecimalTokenAddresses = nonZrxERC20EighteenDecimalTokenAddresses;
|
this._nonZrxERC20EighteenDecimalTokenAddresses = nonZrxERC20EighteenDecimalTokenAddresses;
|
||||||
this._erc20FiveDecimalTokenAddresses = erc20FiveDecimalTokenAddresses;
|
this._erc20FiveDecimalTokenAddresses = erc20FiveDecimalTokenAddresses;
|
||||||
|
this._erc20ZeroDecimalTokenAddresses = erc20ZeroDecimalTokenAddresses;
|
||||||
this._erc721Token = erc721Token;
|
this._erc721Token = erc721Token;
|
||||||
this._erc721Balances = erc721Balances;
|
this._erc721Balances = erc721Balances;
|
||||||
this._exchangeAddress = exchangeAddress;
|
this._exchangeAddress = exchangeAddress;
|
||||||
@ -89,6 +94,9 @@ export class OrderFactoryFromScenario {
|
|||||||
erc721MakerAssetIds[0],
|
erc721MakerAssetIds[0],
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case AssetDataScenario.ERC20ZeroDecimals:
|
||||||
|
makerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[0]);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
|
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
|
||||||
}
|
}
|
||||||
@ -109,6 +117,9 @@ export class OrderFactoryFromScenario {
|
|||||||
erc721TakerAssetIds[0],
|
erc721TakerAssetIds[0],
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case AssetDataScenario.ERC20ZeroDecimals:
|
||||||
|
takerAssetData = assetDataUtils.encodeERC20AssetData(this._erc20ZeroDecimalTokenAddresses[1]);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
|
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
|
||||||
}
|
}
|
||||||
@ -126,6 +137,9 @@ export class OrderFactoryFromScenario {
|
|||||||
case AssetDataScenario.ERC721:
|
case AssetDataScenario.ERC721:
|
||||||
makerAssetAmount = ONE_NFT_UNIT;
|
makerAssetAmount = ONE_NFT_UNIT;
|
||||||
break;
|
break;
|
||||||
|
case AssetDataScenario.ERC20ZeroDecimals:
|
||||||
|
makerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
|
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
|
||||||
}
|
}
|
||||||
@ -142,6 +156,9 @@ export class OrderFactoryFromScenario {
|
|||||||
case AssetDataScenario.ERC721:
|
case AssetDataScenario.ERC721:
|
||||||
makerAssetAmount = ONE_NFT_UNIT;
|
makerAssetAmount = ONE_NFT_UNIT;
|
||||||
break;
|
break;
|
||||||
|
case AssetDataScenario.ERC20ZeroDecimals:
|
||||||
|
makerAssetAmount = TEN_UNITS_ZERO_DECIMALS;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
|
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.makerAssetDataScenario);
|
||||||
}
|
}
|
||||||
@ -166,6 +183,9 @@ export class OrderFactoryFromScenario {
|
|||||||
case AssetDataScenario.ERC721:
|
case AssetDataScenario.ERC721:
|
||||||
takerAssetAmount = ONE_NFT_UNIT;
|
takerAssetAmount = ONE_NFT_UNIT;
|
||||||
break;
|
break;
|
||||||
|
case AssetDataScenario.ERC20ZeroDecimals:
|
||||||
|
takerAssetAmount = ONE_THOUSAND_UNITS_ZERO_DECIMALS;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
|
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
|
||||||
}
|
}
|
||||||
@ -182,6 +202,9 @@ export class OrderFactoryFromScenario {
|
|||||||
case AssetDataScenario.ERC721:
|
case AssetDataScenario.ERC721:
|
||||||
takerAssetAmount = ONE_NFT_UNIT;
|
takerAssetAmount = ONE_NFT_UNIT;
|
||||||
break;
|
break;
|
||||||
|
case AssetDataScenario.ERC20ZeroDecimals:
|
||||||
|
takerAssetAmount = TEN_UNITS_ZERO_DECIMALS;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
|
throw errorUtils.spawnSwitchErr('AssetDataScenario', orderScenario.takerAssetDataScenario);
|
||||||
}
|
}
|
||||||
|
@ -177,10 +177,11 @@ export enum ExpirationTimeSecondsScenario {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum AssetDataScenario {
|
export enum AssetDataScenario {
|
||||||
ERC721 = 'ERC721',
|
ERC20ZeroDecimals = 'ERC20_ZERO_DECIMALS',
|
||||||
ZRXFeeToken = 'ZRX_FEE_TOKEN',
|
ZRXFeeToken = 'ZRX_FEE_TOKEN',
|
||||||
ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS',
|
ERC20FiveDecimals = 'ERC20_FIVE_DECIMALS',
|
||||||
ERC20NonZRXEighteenDecimals = 'ERC20_NON_ZRX_EIGHTEEN_DECIMALS',
|
ERC20NonZRXEighteenDecimals = 'ERC20_NON_ZRX_EIGHTEEN_DECIMALS',
|
||||||
|
ERC721 = 'ERC721',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TakerAssetFillAmountScenario {
|
export enum TakerAssetFillAmountScenario {
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^4.1.0",
|
"mocha": "^4.1.0",
|
||||||
"npm-run-all": "^4.1.2",
|
"npm-run-all": "^4.1.2",
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/monorepo-scripts": "^1.0.5",
|
"@0xproject/monorepo-scripts": "^1.0.5",
|
||||||
"@0xproject/tslint-config": "^1.0.5",
|
"@0xproject/tslint-config": "^1.0.5",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
"tslint": "5.11.0",
|
"tslint": "5.11.0",
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
"@0xproject/sol-compiler": "^1.0.5",
|
"@0xproject/sol-compiler": "^1.0.5",
|
||||||
"@0xproject/tslint-config": "^1.0.5",
|
"@0xproject/tslint-config": "^1.0.5",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"npm-run-all": "^4.1.2",
|
"npm-run-all": "^4.1.2",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
|
@ -60,7 +60,7 @@
|
|||||||
"@types/lodash.values": "^4.3.3",
|
"@types/lodash.values": "^4.3.3",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"lodash.foreach": "^4.5.0",
|
"lodash.foreach": "^4.5.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
"@0xproject/tslint-config": "^1.0.5",
|
"@0xproject/tslint-config": "^1.0.5",
|
||||||
"@0xproject/types": "^1.0.1-rc.4",
|
"@0xproject/types": "^1.0.1-rc.4",
|
||||||
"@types/yargs": "^10.0.0",
|
"@types/yargs": "^10.0.0",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"npm-run-all": "^4.1.2",
|
"npm-run-all": "^4.1.2",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
|
@ -1,4 +1,22 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note":
|
||||||
|
"Update marketUtils api such that all optional parameters are bundled into one optional param and more defaults are provided",
|
||||||
|
"pr": 954
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.0.1-rc.3",
|
"version": "1.0.1-rc.3",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"chai-bignumber": "^2.0.1",
|
"chai-bignumber": "^2.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^4.1.0",
|
"mocha": "^4.1.0",
|
||||||
|
@ -25,3 +25,5 @@ export { EIP712Utils } from './eip712_utils';
|
|||||||
export { OrderValidationUtils } from './order_validation_utils';
|
export { OrderValidationUtils } from './order_validation_utils';
|
||||||
export { ExchangeTransferSimulator } from './exchange_transfer_simulator';
|
export { ExchangeTransferSimulator } from './exchange_transfer_simulator';
|
||||||
export { marketUtils } from './market_utils';
|
export { marketUtils } from './market_utils';
|
||||||
|
export { rateUtils } from './rate_utils';
|
||||||
|
export { sortingUtils } from './sorting_utils';
|
||||||
|
@ -1,46 +1,51 @@
|
|||||||
import { schemas } from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import { SignedOrder } from '@0xproject/types';
|
import { Order } from '@0xproject/types';
|
||||||
import { BigNumber } from '@0xproject/utils';
|
import { BigNumber } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { assert } from './assert';
|
import { assert } from './assert';
|
||||||
import { constants } from './constants';
|
import { constants } from './constants';
|
||||||
|
import { FindFeeOrdersThatCoverFeesForTargetOrdersOpts, FindOrdersThatCoverMakerAssetFillAmountOpts } from './types';
|
||||||
|
|
||||||
export const marketUtils = {
|
export const marketUtils = {
|
||||||
/**
|
/**
|
||||||
* Takes an array of orders and returns a subset of those orders that has enough makerAssetAmount (taking into account on-chain balances,
|
* Takes an array of orders and returns a subset of those orders that has enough makerAssetAmount
|
||||||
* allowances, and partial fills) in order to fill the input makerAssetFillAmount plus slippageBufferAmount. Iterates from first order to last.
|
* in order to fill the input makerAssetFillAmount plus slippageBufferAmount. Iterates from first order to last order.
|
||||||
* Sort the input by ascending rate in order to get the subset of orders that will cost the least ETH.
|
* Sort the input by ascending rate in order to get the subset of orders that will cost the least ETH.
|
||||||
* @param signedOrders An array of objects that conform to the SignedOrder interface. All orders should specify the same makerAsset.
|
* @param orders An array of objects that extend the Order interface. All orders should specify the same makerAsset.
|
||||||
* All orders should specify WETH as the takerAsset.
|
* All orders should specify WETH as the takerAsset.
|
||||||
* @param remainingFillableMakerAssetAmounts An array of BigNumbers corresponding to the signedOrders parameter.
|
|
||||||
* You can use OrderStateUtils @0xproject/order-utils to perform blockchain lookups
|
|
||||||
* for these values.
|
|
||||||
* @param makerAssetFillAmount The amount of makerAsset desired to be filled.
|
* @param makerAssetFillAmount The amount of makerAsset desired to be filled.
|
||||||
* @param slippageBufferAmount An additional amount of makerAsset to be covered by the result in case of trade collisions or partial fills.
|
* @param opts Optional arguments this function accepts.
|
||||||
* @return Resulting orders and remaining fill amount that could not be covered by the input.
|
* @return Resulting orders and remaining fill amount that could not be covered by the input.
|
||||||
*/
|
*/
|
||||||
findOrdersThatCoverMakerAssetFillAmount(
|
findOrdersThatCoverMakerAssetFillAmount<T extends Order>(
|
||||||
signedOrders: SignedOrder[],
|
orders: T[],
|
||||||
remainingFillableMakerAssetAmounts: BigNumber[],
|
|
||||||
makerAssetFillAmount: BigNumber,
|
makerAssetFillAmount: BigNumber,
|
||||||
slippageBufferAmount: BigNumber = constants.ZERO_AMOUNT,
|
opts?: FindOrdersThatCoverMakerAssetFillAmountOpts,
|
||||||
): { resultOrders: SignedOrder[]; remainingFillAmount: BigNumber } {
|
): { resultOrders: T[]; remainingFillAmount: BigNumber } {
|
||||||
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
|
assert.doesConformToSchema('orders', orders, schemas.ordersSchema);
|
||||||
|
assert.isValidBaseUnitAmount('makerAssetFillAmount', makerAssetFillAmount);
|
||||||
|
// try to get remainingFillableMakerAssetAmounts from opts, if it's not there, use makerAssetAmount values from orders
|
||||||
|
const remainingFillableMakerAssetAmounts = _.get(
|
||||||
|
opts,
|
||||||
|
'remainingFillableMakerAssetAmounts',
|
||||||
|
_.map(orders, order => order.makerAssetAmount),
|
||||||
|
) as BigNumber[];
|
||||||
_.forEach(remainingFillableMakerAssetAmounts, (amount, index) =>
|
_.forEach(remainingFillableMakerAssetAmounts, (amount, index) =>
|
||||||
assert.isValidBaseUnitAmount(`remainingFillableMakerAssetAmount[${index}]`, amount),
|
assert.isValidBaseUnitAmount(`remainingFillableMakerAssetAmount[${index}]`, amount),
|
||||||
);
|
);
|
||||||
assert.isValidBaseUnitAmount('makerAssetFillAmount', makerAssetFillAmount);
|
|
||||||
assert.isValidBaseUnitAmount('slippageBufferAmount', slippageBufferAmount);
|
|
||||||
assert.assert(
|
assert.assert(
|
||||||
signedOrders.length === remainingFillableMakerAssetAmounts.length,
|
orders.length === remainingFillableMakerAssetAmounts.length,
|
||||||
'Expected signedOrders.length to equal remainingFillableMakerAssetAmounts.length',
|
'Expected orders.length to equal opts.remainingFillableMakerAssetAmounts.length',
|
||||||
);
|
);
|
||||||
|
// try to get slippageBufferAmount from opts, if it's not there, default to 0
|
||||||
|
const slippageBufferAmount = _.get(opts, 'slippageBufferAmount', constants.ZERO_AMOUNT) as BigNumber;
|
||||||
|
assert.isValidBaseUnitAmount('opts.slippageBufferAmount', slippageBufferAmount);
|
||||||
// calculate total amount of makerAsset needed to be filled
|
// calculate total amount of makerAsset needed to be filled
|
||||||
const totalFillAmount = makerAssetFillAmount.plus(slippageBufferAmount);
|
const totalFillAmount = makerAssetFillAmount.plus(slippageBufferAmount);
|
||||||
// iterate through the signedOrders input from left to right until we have enough makerAsset to fill totalFillAmount
|
// iterate through the orders input from left to right until we have enough makerAsset to fill totalFillAmount
|
||||||
const result = _.reduce(
|
const result = _.reduce(
|
||||||
signedOrders,
|
orders,
|
||||||
({ resultOrders, remainingFillAmount }, order, index) => {
|
({ resultOrders, remainingFillAmount }, order, index) => {
|
||||||
if (remainingFillAmount.lessThanOrEqualTo(constants.ZERO_AMOUNT)) {
|
if (remainingFillAmount.lessThanOrEqualTo(constants.ZERO_AMOUNT)) {
|
||||||
return { resultOrders, remainingFillAmount: constants.ZERO_AMOUNT };
|
return { resultOrders, remainingFillAmount: constants.ZERO_AMOUNT };
|
||||||
@ -59,55 +64,61 @@ export const marketUtils = {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ resultOrders: [] as SignedOrder[], remainingFillAmount: totalFillAmount },
|
{ resultOrders: [] as T[], remainingFillAmount: totalFillAmount },
|
||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Takes an array of orders and an array of feeOrders. Returns a subset of the feeOrders that has enough ZRX (taking into account
|
* Takes an array of orders and an array of feeOrders. Returns a subset of the feeOrders that has enough ZRX
|
||||||
* on-chain balances, allowances, and partial fills) in order to fill the takerFees required by signedOrders plus a
|
* in order to fill the takerFees required by orders plus a slippageBufferAmount.
|
||||||
* slippageBufferAmount. Iterates from first feeOrder to last. Sort the feeOrders by ascending rate in order to get the subset of
|
* Iterates from first feeOrder to last. Sort the feeOrders by ascending rate in order to get the subset of
|
||||||
* feeOrders that will cost the least ETH.
|
* feeOrders that will cost the least ETH.
|
||||||
* @param signedOrders An array of objects that conform to the SignedOrder interface. All orders should specify ZRX as
|
* @param orders An array of objects that extend the Order interface. All orders should specify ZRX as
|
||||||
* the makerAsset and WETH as the takerAsset.
|
* the makerAsset and WETH as the takerAsset.
|
||||||
* @param remainingFillableMakerAssetAmounts An array of BigNumbers corresponding to the signedOrders parameter.
|
* @param feeOrders An array of objects that extend the Order interface. All orders should specify ZRX as
|
||||||
* You can use OrderStateUtils @0xproject/order-utils to perform blockchain lookups
|
|
||||||
* for these values.
|
|
||||||
* @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders should specify ZRX as
|
|
||||||
* the makerAsset and WETH as the takerAsset.
|
* the makerAsset and WETH as the takerAsset.
|
||||||
* @param remainingFillableFeeAmounts An array of BigNumbers corresponding to the signedFeeOrders parameter.
|
* @param opts Optional arguments this function accepts.
|
||||||
* You can use OrderStateUtils @0xproject/order-utils to perform blockchain lookups
|
|
||||||
* for these values.
|
|
||||||
* @param slippageBufferAmount An additional amount of fee to be covered by the result in case of trade collisions or partial fills.
|
|
||||||
* @return Resulting orders and remaining fee amount that could not be covered by the input.
|
* @return Resulting orders and remaining fee amount that could not be covered by the input.
|
||||||
*/
|
*/
|
||||||
findFeeOrdersThatCoverFeesForTargetOrders(
|
findFeeOrdersThatCoverFeesForTargetOrders<T extends Order>(
|
||||||
signedOrders: SignedOrder[],
|
orders: T[],
|
||||||
remainingFillableMakerAssetAmounts: BigNumber[],
|
feeOrders: T[],
|
||||||
signedFeeOrders: SignedOrder[],
|
opts?: FindFeeOrdersThatCoverFeesForTargetOrdersOpts,
|
||||||
remainingFillableFeeAmounts: BigNumber[],
|
): { resultOrders: T[]; remainingFeeAmount: BigNumber } {
|
||||||
slippageBufferAmount: BigNumber = constants.ZERO_AMOUNT,
|
assert.doesConformToSchema('orders', orders, schemas.ordersSchema);
|
||||||
): { resultOrders: SignedOrder[]; remainingFeeAmount: BigNumber } {
|
assert.doesConformToSchema('feeOrders', feeOrders, schemas.ordersSchema);
|
||||||
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
|
// try to get remainingFillableMakerAssetAmounts from opts, if it's not there, use makerAssetAmount values from orders
|
||||||
|
const remainingFillableMakerAssetAmounts = _.get(
|
||||||
|
opts,
|
||||||
|
'remainingFillableMakerAssetAmounts',
|
||||||
|
_.map(orders, order => order.makerAssetAmount),
|
||||||
|
) as BigNumber[];
|
||||||
_.forEach(remainingFillableMakerAssetAmounts, (amount, index) =>
|
_.forEach(remainingFillableMakerAssetAmounts, (amount, index) =>
|
||||||
assert.isValidBaseUnitAmount(`remainingFillableMakerAssetAmount[${index}]`, amount),
|
assert.isValidBaseUnitAmount(`remainingFillableMakerAssetAmount[${index}]`, amount),
|
||||||
);
|
);
|
||||||
assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema);
|
assert.assert(
|
||||||
|
orders.length === remainingFillableMakerAssetAmounts.length,
|
||||||
|
'Expected orders.length to equal opts.remainingFillableMakerAssetAmounts.length',
|
||||||
|
);
|
||||||
|
// try to get remainingFillableFeeAmounts from opts, if it's not there, use makerAssetAmount values from feeOrders
|
||||||
|
const remainingFillableFeeAmounts = _.get(
|
||||||
|
opts,
|
||||||
|
'remainingFillableFeeAmounts',
|
||||||
|
_.map(feeOrders, order => order.makerAssetAmount),
|
||||||
|
) as BigNumber[];
|
||||||
_.forEach(remainingFillableFeeAmounts, (amount, index) =>
|
_.forEach(remainingFillableFeeAmounts, (amount, index) =>
|
||||||
assert.isValidBaseUnitAmount(`remainingFillableFeeAmounts[${index}]`, amount),
|
assert.isValidBaseUnitAmount(`remainingFillableFeeAmounts[${index}]`, amount),
|
||||||
);
|
);
|
||||||
assert.isValidBaseUnitAmount('slippageBufferAmount', slippageBufferAmount);
|
|
||||||
assert.assert(
|
assert.assert(
|
||||||
signedOrders.length === remainingFillableMakerAssetAmounts.length,
|
feeOrders.length === remainingFillableFeeAmounts.length,
|
||||||
'Expected signedOrders.length to equal remainingFillableMakerAssetAmounts.length',
|
'Expected feeOrders.length to equal opts.remainingFillableFeeAmounts.length',
|
||||||
);
|
);
|
||||||
assert.assert(
|
// try to get slippageBufferAmount from opts, if it's not there, default to 0
|
||||||
signedOrders.length === remainingFillableMakerAssetAmounts.length,
|
const slippageBufferAmount = _.get(opts, 'slippageBufferAmount', constants.ZERO_AMOUNT) as BigNumber;
|
||||||
'Expected signedFeeOrders.length to equal remainingFillableFeeAmounts.length',
|
assert.isValidBaseUnitAmount('opts.slippageBufferAmount', slippageBufferAmount);
|
||||||
);
|
// calculate total amount of ZRX needed to fill orders
|
||||||
// calculate total amount of ZRX needed to fill signedOrders
|
|
||||||
const totalFeeAmount = _.reduce(
|
const totalFeeAmount = _.reduce(
|
||||||
signedOrders,
|
orders,
|
||||||
(accFees, order, index) => {
|
(accFees, order, index) => {
|
||||||
const makerAssetAmountAvailable = remainingFillableMakerAssetAmounts[index];
|
const makerAssetAmountAvailable = remainingFillableMakerAssetAmounts[index];
|
||||||
const feeToFillMakerAssetAmountAvailable = makerAssetAmountAvailable
|
const feeToFillMakerAssetAmountAvailable = makerAssetAmountAvailable
|
||||||
@ -118,10 +129,12 @@ export const marketUtils = {
|
|||||||
constants.ZERO_AMOUNT,
|
constants.ZERO_AMOUNT,
|
||||||
);
|
);
|
||||||
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
||||||
signedFeeOrders,
|
feeOrders,
|
||||||
remainingFillableFeeAmounts,
|
|
||||||
totalFeeAmount,
|
totalFeeAmount,
|
||||||
|
{
|
||||||
|
remainingFillableMakerAssetAmounts: remainingFillableFeeAmounts,
|
||||||
slippageBufferAmount,
|
slippageBufferAmount,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
resultOrders,
|
resultOrders,
|
||||||
|
@ -11,6 +11,7 @@ import { BigNumber } from '@0xproject/utils';
|
|||||||
import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
|
import { AbstractBalanceAndProxyAllowanceFetcher } from './abstract/abstract_balance_and_proxy_allowance_fetcher';
|
||||||
import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
|
import { AbstractOrderFilledCancelledFetcher } from './abstract/abstract_order_filled_cancelled_fetcher';
|
||||||
import { orderHashUtils } from './order_hash';
|
import { orderHashUtils } from './order_hash';
|
||||||
|
import { OrderValidationUtils } from './order_validation_utils';
|
||||||
import { RemainingFillableCalculator } from './remaining_fillable_calculator';
|
import { RemainingFillableCalculator } from './remaining_fillable_calculator';
|
||||||
import { utils } from './utils';
|
import { utils } from './utils';
|
||||||
|
|
||||||
@ -22,9 +23,16 @@ interface SidedOrderRelevantState {
|
|||||||
traderFeeProxyAllowance: BigNumber;
|
traderFeeProxyAllowance: BigNumber;
|
||||||
filledTakerAssetAmount: BigNumber;
|
filledTakerAssetAmount: BigNumber;
|
||||||
remainingFillableAssetAmount: BigNumber;
|
remainingFillableAssetAmount: BigNumber;
|
||||||
|
isOrderCancelled: boolean;
|
||||||
}
|
}
|
||||||
|
interface OrderValidResult {
|
||||||
const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001;
|
isValid: true;
|
||||||
|
}
|
||||||
|
interface OrderInvalidResult {
|
||||||
|
isValid: false;
|
||||||
|
error: ExchangeContractErrs;
|
||||||
|
}
|
||||||
|
type OrderValidationResult = OrderValidResult | OrderInvalidResult;
|
||||||
|
|
||||||
export class OrderStateUtils {
|
export class OrderStateUtils {
|
||||||
private readonly _balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher;
|
private readonly _balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher;
|
||||||
@ -32,64 +40,56 @@ export class OrderStateUtils {
|
|||||||
private static _validateIfOrderIsValid(
|
private static _validateIfOrderIsValid(
|
||||||
signedOrder: SignedOrder,
|
signedOrder: SignedOrder,
|
||||||
sidedOrderRelevantState: SidedOrderRelevantState,
|
sidedOrderRelevantState: SidedOrderRelevantState,
|
||||||
): void {
|
): OrderValidationResult {
|
||||||
const isMakerSide = sidedOrderRelevantState.isMakerSide;
|
const isMakerSide = sidedOrderRelevantState.isMakerSide;
|
||||||
|
if (sidedOrderRelevantState.isOrderCancelled) {
|
||||||
|
return { isValid: false, error: ExchangeContractErrs.OrderCancelled };
|
||||||
|
}
|
||||||
const availableTakerAssetAmount = signedOrder.takerAssetAmount.minus(
|
const availableTakerAssetAmount = signedOrder.takerAssetAmount.minus(
|
||||||
sidedOrderRelevantState.filledTakerAssetAmount,
|
sidedOrderRelevantState.filledTakerAssetAmount,
|
||||||
);
|
);
|
||||||
if (availableTakerAssetAmount.eq(0)) {
|
if (availableTakerAssetAmount.eq(0)) {
|
||||||
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
return { isValid: false, error: ExchangeContractErrs.OrderRemainingFillAmountZero };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sidedOrderRelevantState.traderBalance.eq(0)) {
|
if (sidedOrderRelevantState.traderBalance.eq(0)) {
|
||||||
throw new Error(
|
const error = isMakerSide
|
||||||
isMakerSide
|
|
||||||
? ExchangeContractErrs.InsufficientMakerBalance
|
? ExchangeContractErrs.InsufficientMakerBalance
|
||||||
: ExchangeContractErrs.InsufficientTakerBalance,
|
: ExchangeContractErrs.InsufficientTakerBalance;
|
||||||
);
|
return { isValid: false, error };
|
||||||
}
|
}
|
||||||
if (sidedOrderRelevantState.traderProxyAllowance.eq(0)) {
|
if (sidedOrderRelevantState.traderProxyAllowance.eq(0)) {
|
||||||
throw new Error(
|
const error = isMakerSide
|
||||||
isMakerSide
|
|
||||||
? ExchangeContractErrs.InsufficientMakerAllowance
|
? ExchangeContractErrs.InsufficientMakerAllowance
|
||||||
: ExchangeContractErrs.InsufficientTakerAllowance,
|
: ExchangeContractErrs.InsufficientTakerAllowance;
|
||||||
);
|
return { isValid: false, error };
|
||||||
}
|
}
|
||||||
if (!signedOrder.makerFee.eq(0)) {
|
if (!signedOrder.makerFee.eq(0)) {
|
||||||
if (sidedOrderRelevantState.traderFeeBalance.eq(0)) {
|
if (sidedOrderRelevantState.traderFeeBalance.eq(0)) {
|
||||||
throw new Error(
|
const error = isMakerSide
|
||||||
isMakerSide
|
|
||||||
? ExchangeContractErrs.InsufficientMakerFeeBalance
|
? ExchangeContractErrs.InsufficientMakerFeeBalance
|
||||||
: ExchangeContractErrs.InsufficientTakerFeeBalance,
|
: ExchangeContractErrs.InsufficientTakerFeeBalance;
|
||||||
);
|
return { isValid: false, error };
|
||||||
}
|
}
|
||||||
if (sidedOrderRelevantState.traderFeeProxyAllowance.eq(0)) {
|
if (sidedOrderRelevantState.traderFeeProxyAllowance.eq(0)) {
|
||||||
throw new Error(
|
const error = isMakerSide
|
||||||
isMakerSide
|
|
||||||
? ExchangeContractErrs.InsufficientMakerFeeAllowance
|
? ExchangeContractErrs.InsufficientMakerFeeAllowance
|
||||||
: ExchangeContractErrs.InsufficientTakerFeeAllowance,
|
: ExchangeContractErrs.InsufficientTakerFeeAllowance;
|
||||||
|
return { isValid: false, error };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 };
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
constructor(
|
constructor(
|
||||||
balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher,
|
balanceAndProxyAllowanceFetcher: AbstractBalanceAndProxyAllowanceFetcher,
|
||||||
@ -101,6 +101,7 @@ export class OrderStateUtils {
|
|||||||
public async getOpenOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
|
public async getOpenOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
|
||||||
const orderRelevantState = await this.getOpenOrderRelevantStateAsync(signedOrder);
|
const orderRelevantState = await this.getOpenOrderRelevantStateAsync(signedOrder);
|
||||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
|
const isOrderCancelled = await this._orderFilledCancelledFetcher.isOrderCancelledAsync(orderHash);
|
||||||
const sidedOrderRelevantState = {
|
const sidedOrderRelevantState = {
|
||||||
isMakerSide: true,
|
isMakerSide: true,
|
||||||
traderBalance: orderRelevantState.makerBalance,
|
traderBalance: orderRelevantState.makerBalance,
|
||||||
@ -109,20 +110,21 @@ export class OrderStateUtils {
|
|||||||
traderFeeProxyAllowance: orderRelevantState.makerFeeProxyAllowance,
|
traderFeeProxyAllowance: orderRelevantState.makerFeeProxyAllowance,
|
||||||
filledTakerAssetAmount: orderRelevantState.filledTakerAssetAmount,
|
filledTakerAssetAmount: orderRelevantState.filledTakerAssetAmount,
|
||||||
remainingFillableAssetAmount: orderRelevantState.remainingFillableMakerAssetAmount,
|
remainingFillableAssetAmount: orderRelevantState.remainingFillableMakerAssetAmount,
|
||||||
|
isOrderCancelled,
|
||||||
};
|
};
|
||||||
try {
|
const orderValidationResult = OrderStateUtils._validateIfOrderIsValid(signedOrder, sidedOrderRelevantState);
|
||||||
OrderStateUtils._validateIfOrderIsValid(signedOrder, sidedOrderRelevantState);
|
if (orderValidationResult.isValid) {
|
||||||
const orderState: OrderStateValid = {
|
const orderState: OrderStateValid = {
|
||||||
isValid: true,
|
isValid: true,
|
||||||
orderHash,
|
orderHash,
|
||||||
orderRelevantState,
|
orderRelevantState,
|
||||||
};
|
};
|
||||||
return orderState;
|
return orderState;
|
||||||
} catch (err) {
|
} else {
|
||||||
const orderState: OrderStateInvalid = {
|
const orderState: OrderStateInvalid = {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
orderHash,
|
orderHash,
|
||||||
error: err.message,
|
error: orderValidationResult.error,
|
||||||
};
|
};
|
||||||
return orderState;
|
return orderState;
|
||||||
}
|
}
|
||||||
@ -278,6 +280,7 @@ export class OrderStateUtils {
|
|||||||
traderFeeProxyAllowance,
|
traderFeeProxyAllowance,
|
||||||
filledTakerAssetAmount,
|
filledTakerAssetAmount,
|
||||||
remainingFillableAssetAmount,
|
remainingFillableAssetAmount,
|
||||||
|
isOrderCancelled,
|
||||||
};
|
};
|
||||||
return sidedOrderRelevantState;
|
return sidedOrderRelevantState;
|
||||||
}
|
}
|
||||||
|
48
packages/order-utils/src/rate_utils.ts
Normal file
48
packages/order-utils/src/rate_utils.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
|
import { Order } from '@0xproject/types';
|
||||||
|
import { BigNumber } from '@0xproject/utils';
|
||||||
|
|
||||||
|
import { assert } from './assert';
|
||||||
|
import { constants } from './constants';
|
||||||
|
|
||||||
|
export const rateUtils = {
|
||||||
|
/**
|
||||||
|
* Takes an order and calculates the fee adjusted rate (takerAsset/makerAsset) by calculating how much takerAsset
|
||||||
|
* is required to cover the fees (feeRate * takerFee), adding the takerAssetAmount and dividing by makerAssetAmount
|
||||||
|
* @param order An object that conforms to the order interface
|
||||||
|
* @param feeRate The market rate of ZRX denominated in takerAssetAmount
|
||||||
|
* (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX)
|
||||||
|
* Defaults to 0
|
||||||
|
* @return The rate (takerAsset/makerAsset) of the order adjusted for fees
|
||||||
|
*/
|
||||||
|
getFeeAdjustedRateOfOrder(order: Order, feeRate: BigNumber = constants.ZERO_AMOUNT): BigNumber {
|
||||||
|
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
||||||
|
assert.isBigNumber('feeRate', feeRate);
|
||||||
|
assert.assert(
|
||||||
|
feeRate.gte(constants.ZERO_AMOUNT),
|
||||||
|
`Expected feeRate: ${feeRate} to be greater than or equal to 0`,
|
||||||
|
);
|
||||||
|
const takerAssetAmountNeededToPayForFees = order.takerFee.mul(feeRate);
|
||||||
|
const totalTakerAssetAmount = takerAssetAmountNeededToPayForFees.plus(order.takerAssetAmount);
|
||||||
|
const rate = totalTakerAssetAmount.div(order.makerAssetAmount);
|
||||||
|
return rate;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Takes a fee order (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH) and calculates
|
||||||
|
* the fee adjusted rate (WETH/ZRX) by dividing the takerAssetAmount by the makerAmount minus the takerFee
|
||||||
|
* @param feeOrder An object that conforms to the order interface
|
||||||
|
* @return The rate (WETH/ZRX) of the fee order adjusted for fees
|
||||||
|
*/
|
||||||
|
getFeeAdjustedRateOfFeeOrder(feeOrder: Order): BigNumber {
|
||||||
|
assert.doesConformToSchema('feeOrder', feeOrder, schemas.orderSchema);
|
||||||
|
const zrxAmountAfterFees = feeOrder.makerAssetAmount.sub(feeOrder.takerFee);
|
||||||
|
assert.assert(
|
||||||
|
zrxAmountAfterFees.greaterThan(constants.ZERO_AMOUNT),
|
||||||
|
`Expected takerFee: ${JSON.stringify(feeOrder.takerFee)} to be less than makerAssetAmount: ${JSON.stringify(
|
||||||
|
feeOrder.makerAssetAmount,
|
||||||
|
)}`,
|
||||||
|
);
|
||||||
|
const rate = feeOrder.takerAssetAmount.div(zrxAmountAfterFees);
|
||||||
|
return rate;
|
||||||
|
},
|
||||||
|
};
|
54
packages/order-utils/src/sorting_utils.ts
Normal file
54
packages/order-utils/src/sorting_utils.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
|
import { Order } from '@0xproject/types';
|
||||||
|
import { BigNumber } from '@0xproject/utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { assert } from './assert';
|
||||||
|
import { constants } from './constants';
|
||||||
|
import { rateUtils } from './rate_utils';
|
||||||
|
|
||||||
|
export const sortingUtils = {
|
||||||
|
/**
|
||||||
|
* Takes an array of orders and sorts them by takerAsset/makerAsset rate in ascending order (best rate first).
|
||||||
|
* Adjusts the rate of each order according to the feeRate and takerFee for that order.
|
||||||
|
* @param orders An array of objects that extend the Order interface. All orders should specify ZRX as
|
||||||
|
* the makerAsset and WETH as the takerAsset.
|
||||||
|
* @param feeRate The market rate of ZRX denominated in takerAssetAmount
|
||||||
|
* (ex. feeRate is 0.1 takerAsset/ZRX if it takes 1 unit of takerAsset to buy 10 ZRX)
|
||||||
|
* Defaults to 0
|
||||||
|
* @return The input orders sorted by rate in ascending order
|
||||||
|
*/
|
||||||
|
sortOrdersByFeeAdjustedRate<T extends Order>(orders: T[], feeRate: BigNumber = constants.ZERO_AMOUNT): T[] {
|
||||||
|
assert.doesConformToSchema('orders', orders, schemas.ordersSchema);
|
||||||
|
assert.isBigNumber('feeRate', feeRate);
|
||||||
|
const rateCalculator = (order: Order) => rateUtils.getFeeAdjustedRateOfOrder(order, feeRate);
|
||||||
|
const sortedOrders = sortOrders(orders, rateCalculator);
|
||||||
|
return sortedOrders;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Takes an array of fee orders (makerAssetData corresponds to ZRX and takerAssetData corresponds to WETH)
|
||||||
|
* and sorts them by rate in ascending order (best rate first). Adjusts the rate according to the takerFee.
|
||||||
|
* @param feeOrders An array of objects that extend the Order interface. All orders should specify ZRX as
|
||||||
|
* the makerAsset and WETH as the takerAsset.
|
||||||
|
* @return The input orders sorted by rate in ascending order
|
||||||
|
*/
|
||||||
|
sortFeeOrdersByFeeAdjustedRate(feeOrders: Order[]): Order[] {
|
||||||
|
assert.doesConformToSchema('feeOrders', feeOrders, schemas.ordersSchema);
|
||||||
|
const rateCalculator = rateUtils.getFeeAdjustedRateOfFeeOrder.bind(rateUtils);
|
||||||
|
const sortedOrders = sortOrders(feeOrders, rateCalculator);
|
||||||
|
return sortedOrders;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
type RateCalculator = (order: Order) => BigNumber;
|
||||||
|
|
||||||
|
// takes an array of orders, copies them, and sorts the copy based on the rate definition provided by rateCalculator
|
||||||
|
function sortOrders<T extends Order>(orders: T[], rateCalculator: RateCalculator): T[] {
|
||||||
|
const copiedOrders = _.cloneDeep(orders);
|
||||||
|
copiedOrders.sort((firstOrder, secondOrder) => {
|
||||||
|
const firstOrderRate = rateCalculator(firstOrder);
|
||||||
|
const secondOrderRate = rateCalculator(secondOrder);
|
||||||
|
return firstOrderRate.comparedTo(secondOrderRate);
|
||||||
|
});
|
||||||
|
return copiedOrders;
|
||||||
|
}
|
@ -41,3 +41,31 @@ export interface CreateOrderOpts {
|
|||||||
salt?: BigNumber;
|
salt?: BigNumber;
|
||||||
expirationTimeSeconds?: BigNumber;
|
expirationTimeSeconds?: BigNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter.
|
||||||
|
* You can use `OrderStateUtils` `@0xproject/order-utils` to perform blockchain lookups for these values.
|
||||||
|
* Defaults to `makerAssetAmount` values from the orders param.
|
||||||
|
* slippageBufferAmount: An additional amount of makerAsset to be covered by the result in case of trade collisions or partial fills.
|
||||||
|
* Defaults to 0
|
||||||
|
*/
|
||||||
|
export interface FindOrdersThatCoverMakerAssetFillAmountOpts {
|
||||||
|
remainingFillableMakerAssetAmounts?: BigNumber[];
|
||||||
|
slippageBufferAmount?: BigNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remainingFillableMakerAssetAmount: An array of BigNumbers corresponding to the `orders` parameter.
|
||||||
|
* You can use `OrderStateUtils` `@0xproject/order-utils` to perform blockchain lookups for these values.
|
||||||
|
* Defaults to `makerAssetAmount` values from the orders param.
|
||||||
|
* remainingFillableFeeAmounts: An array of BigNumbers corresponding to the feeOrders parameter.
|
||||||
|
* You can use OrderStateUtils @0xproject/order-utils to perform blockchain lookups for these values.
|
||||||
|
* Defaults to `makerAssetAmount` values from the feeOrders param.
|
||||||
|
* slippageBufferAmount: An additional amount of fee to be covered by the result in case of trade collisions or partial fills.
|
||||||
|
* Defaults to 0
|
||||||
|
*/
|
||||||
|
export interface FindFeeOrdersThatCoverFeesForTargetOrdersOpts {
|
||||||
|
remainingFillableMakerAssetAmounts?: BigNumber[];
|
||||||
|
remainingFillableFeeAmounts?: BigNumber[];
|
||||||
|
slippageBufferAmount?: BigNumber;
|
||||||
|
}
|
||||||
|
@ -17,7 +17,6 @@ describe('marketUtils', () => {
|
|||||||
it('returns empty and unchanged remainingFillAmount', async () => {
|
it('returns empty and unchanged remainingFillAmount', async () => {
|
||||||
const fillAmount = new BigNumber(10);
|
const fillAmount = new BigNumber(10);
|
||||||
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
||||||
[],
|
|
||||||
[],
|
[],
|
||||||
fillAmount,
|
fillAmount,
|
||||||
);
|
);
|
||||||
@ -34,8 +33,6 @@ describe('marketUtils', () => {
|
|||||||
},
|
},
|
||||||
3,
|
3,
|
||||||
);
|
);
|
||||||
// generate remainingFillableMakerAssetAmounts that equal the makerAssetAmount
|
|
||||||
const remainingFillableMakerAssetAmounts = [makerAssetAmount, makerAssetAmount, makerAssetAmount];
|
|
||||||
it('returns input orders and zero remainingFillAmount when input exactly matches requested fill amount', async () => {
|
it('returns input orders and zero remainingFillAmount when input exactly matches requested fill amount', async () => {
|
||||||
// try to fill 20 units of makerAsset
|
// try to fill 20 units of makerAsset
|
||||||
// include 10 units of slippageBufferAmount
|
// include 10 units of slippageBufferAmount
|
||||||
@ -43,9 +40,10 @@ describe('marketUtils', () => {
|
|||||||
const slippageBufferAmount = new BigNumber(10);
|
const slippageBufferAmount = new BigNumber(10);
|
||||||
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
||||||
inputOrders,
|
inputOrders,
|
||||||
remainingFillableMakerAssetAmounts,
|
|
||||||
fillAmount,
|
fillAmount,
|
||||||
|
{
|
||||||
slippageBufferAmount,
|
slippageBufferAmount,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.deep.equal(inputOrders);
|
expect(resultOrders).to.be.deep.equal(inputOrders);
|
||||||
expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
@ -57,9 +55,10 @@ describe('marketUtils', () => {
|
|||||||
const slippageBufferAmount = new BigNumber(10);
|
const slippageBufferAmount = new BigNumber(10);
|
||||||
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
||||||
inputOrders,
|
inputOrders,
|
||||||
remainingFillableMakerAssetAmounts,
|
|
||||||
fillAmount,
|
fillAmount,
|
||||||
|
{
|
||||||
slippageBufferAmount,
|
slippageBufferAmount,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.deep.equal(inputOrders);
|
expect(resultOrders).to.be.deep.equal(inputOrders);
|
||||||
expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
expect(remainingFillAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
@ -71,9 +70,10 @@ describe('marketUtils', () => {
|
|||||||
const slippageBufferAmount = new BigNumber(5);
|
const slippageBufferAmount = new BigNumber(5);
|
||||||
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
||||||
inputOrders,
|
inputOrders,
|
||||||
remainingFillableMakerAssetAmounts,
|
|
||||||
fillAmount,
|
fillAmount,
|
||||||
|
{
|
||||||
slippageBufferAmount,
|
slippageBufferAmount,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.deep.equal(inputOrders);
|
expect(resultOrders).to.be.deep.equal(inputOrders);
|
||||||
expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(5));
|
expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(5));
|
||||||
@ -83,7 +83,6 @@ describe('marketUtils', () => {
|
|||||||
const fillAmount = new BigNumber(10);
|
const fillAmount = new BigNumber(10);
|
||||||
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
||||||
inputOrders,
|
inputOrders,
|
||||||
remainingFillableMakerAssetAmounts,
|
|
||||||
fillAmount,
|
fillAmount,
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.deep.equal([inputOrders[0]]);
|
expect(resultOrders).to.be.deep.equal([inputOrders[0]]);
|
||||||
@ -94,7 +93,6 @@ describe('marketUtils', () => {
|
|||||||
const fillAmount = new BigNumber(15);
|
const fillAmount = new BigNumber(15);
|
||||||
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
||||||
inputOrders,
|
inputOrders,
|
||||||
remainingFillableMakerAssetAmounts,
|
|
||||||
fillAmount,
|
fillAmount,
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.deep.equal([inputOrders[0], inputOrders[1]]);
|
expect(resultOrders).to.be.deep.equal([inputOrders[0], inputOrders[1]]);
|
||||||
@ -120,8 +118,10 @@ describe('marketUtils', () => {
|
|||||||
const fillAmount = new BigNumber(30);
|
const fillAmount = new BigNumber(30);
|
||||||
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
const { resultOrders, remainingFillAmount } = marketUtils.findOrdersThatCoverMakerAssetFillAmount(
|
||||||
inputOrders,
|
inputOrders,
|
||||||
remainingFillableMakerAssetAmounts,
|
|
||||||
fillAmount,
|
fillAmount,
|
||||||
|
{
|
||||||
|
remainingFillableMakerAssetAmounts,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.deep.equal([inputOrders[1], inputOrders[2]]);
|
expect(resultOrders).to.be.deep.equal([inputOrders[1], inputOrders[2]]);
|
||||||
expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(15));
|
expect(remainingFillAmount).to.be.bignumber.equal(new BigNumber(15));
|
||||||
@ -137,15 +137,11 @@ describe('marketUtils', () => {
|
|||||||
},
|
},
|
||||||
3,
|
3,
|
||||||
);
|
);
|
||||||
// generate remainingFillableFeeAmounts that equal the zrxAmount
|
|
||||||
const remainingFillableFeeAmounts = [zrxAmount, zrxAmount, zrxAmount];
|
|
||||||
describe('no target orders', () => {
|
describe('no target orders', () => {
|
||||||
it('returns empty and zero remainingFeeAmount', async () => {
|
it('returns empty and zero remainingFeeAmount', async () => {
|
||||||
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
||||||
[],
|
|
||||||
[],
|
[],
|
||||||
inputFeeOrders,
|
inputFeeOrders,
|
||||||
remainingFillableFeeAmounts,
|
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.empty;
|
expect(resultOrders).to.be.empty;
|
||||||
expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
@ -168,9 +164,10 @@ describe('marketUtils', () => {
|
|||||||
it('returns empty and non-zero remainingFeeAmount', async () => {
|
it('returns empty and non-zero remainingFeeAmount', async () => {
|
||||||
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
||||||
inputOrders,
|
inputOrders,
|
||||||
|
[],
|
||||||
|
{
|
||||||
remainingFillableMakerAssetAmounts,
|
remainingFillableMakerAssetAmounts,
|
||||||
[],
|
},
|
||||||
[],
|
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.empty;
|
expect(resultOrders).to.be.empty;
|
||||||
expect(remainingFeeAmount).to.be.bignumber.equal(new BigNumber(30));
|
expect(remainingFeeAmount).to.be.bignumber.equal(new BigNumber(30));
|
||||||
@ -185,14 +182,10 @@ describe('marketUtils', () => {
|
|||||||
},
|
},
|
||||||
3,
|
3,
|
||||||
);
|
);
|
||||||
// generate remainingFillableMakerAssetAmounts that equal the makerAssetAmount
|
|
||||||
const remainingFillableMakerAssetAmounts = [makerAssetAmount, makerAssetAmount, makerAssetAmount];
|
|
||||||
it('returns empty and zero remainingFeeAmount', async () => {
|
it('returns empty and zero remainingFeeAmount', async () => {
|
||||||
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
||||||
inputOrders,
|
inputOrders,
|
||||||
remainingFillableMakerAssetAmounts,
|
|
||||||
inputFeeOrders,
|
inputFeeOrders,
|
||||||
remainingFillableFeeAmounts,
|
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.empty;
|
expect(resultOrders).to.be.empty;
|
||||||
expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
@ -210,14 +203,10 @@ describe('marketUtils', () => {
|
|||||||
},
|
},
|
||||||
3,
|
3,
|
||||||
);
|
);
|
||||||
// generate remainingFillableMakerAssetAmounts that equal the makerAssetAmount
|
|
||||||
const remainingFillableMakerAssetAmounts = [makerAssetAmount, makerAssetAmount, makerAssetAmount];
|
|
||||||
it('returns input fee orders and zero remainingFeeAmount', async () => {
|
it('returns input fee orders and zero remainingFeeAmount', async () => {
|
||||||
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
||||||
inputOrders,
|
inputOrders,
|
||||||
remainingFillableMakerAssetAmounts,
|
|
||||||
inputFeeOrders,
|
inputFeeOrders,
|
||||||
remainingFillableFeeAmounts,
|
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.deep.equal(inputFeeOrders);
|
expect(resultOrders).to.be.deep.equal(inputFeeOrders);
|
||||||
expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
@ -243,9 +232,10 @@ describe('marketUtils', () => {
|
|||||||
it('returns first two input fee orders and zero remainingFeeAmount', async () => {
|
it('returns first two input fee orders and zero remainingFeeAmount', async () => {
|
||||||
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
||||||
inputOrders,
|
inputOrders,
|
||||||
remainingFillableMakerAssetAmounts,
|
|
||||||
inputFeeOrders,
|
inputFeeOrders,
|
||||||
remainingFillableFeeAmounts,
|
{
|
||||||
|
remainingFillableMakerAssetAmounts,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.deep.equal([inputFeeOrders[0], inputFeeOrders[1]]);
|
expect(resultOrders).to.be.deep.equal([inputFeeOrders[0], inputFeeOrders[1]]);
|
||||||
expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
expect(remainingFeeAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
@ -263,14 +253,10 @@ describe('marketUtils', () => {
|
|||||||
},
|
},
|
||||||
3,
|
3,
|
||||||
);
|
);
|
||||||
// generate remainingFillableMakerAssetAmounts that equal the makerAssetAmount
|
|
||||||
const remainingFillableMakerAssetAmounts = [makerAssetAmount, makerAssetAmount, makerAssetAmount];
|
|
||||||
it('returns input fee orders and non-zero remainingFeeAmount', async () => {
|
it('returns input fee orders and non-zero remainingFeeAmount', async () => {
|
||||||
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
const { resultOrders, remainingFeeAmount } = marketUtils.findFeeOrdersThatCoverFeesForTargetOrders(
|
||||||
inputOrders,
|
inputOrders,
|
||||||
remainingFillableMakerAssetAmounts,
|
|
||||||
inputFeeOrders,
|
inputFeeOrders,
|
||||||
remainingFillableFeeAmounts,
|
|
||||||
);
|
);
|
||||||
expect(resultOrders).to.be.deep.equal(inputFeeOrders);
|
expect(resultOrders).to.be.deep.equal(inputFeeOrders);
|
||||||
expect(remainingFeeAmount).to.be.bignumber.equal(new BigNumber(30));
|
expect(remainingFeeAmount).to.be.bignumber.equal(new BigNumber(30));
|
||||||
|
124
packages/order-utils/test/order_state_utils_test.ts
Normal file
124
packages/order-utils/test/order_state_utils_test.ts
Normal file
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
55
packages/order-utils/test/rate_utils_test.ts
Normal file
55
packages/order-utils/test/rate_utils_test.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { BigNumber } from '@0xproject/utils';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
import 'mocha';
|
||||||
|
|
||||||
|
import { rateUtils } from '../src';
|
||||||
|
|
||||||
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
|
import { testOrderFactory } from './utils/test_order_factory';
|
||||||
|
|
||||||
|
chaiSetup.configure();
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
describe('rateUtils', () => {
|
||||||
|
const testOrder = testOrderFactory.generateTestSignedOrder({
|
||||||
|
makerAssetAmount: new BigNumber(100),
|
||||||
|
takerAssetAmount: new BigNumber(100),
|
||||||
|
takerFee: new BigNumber(20),
|
||||||
|
});
|
||||||
|
describe('#getFeeAdjustedRateOfOrder', () => {
|
||||||
|
it('throws when feeRate is less than zero', async () => {
|
||||||
|
const feeRate = new BigNumber(-1);
|
||||||
|
expect(() => rateUtils.getFeeAdjustedRateOfOrder(testOrder, feeRate)).to.throw(
|
||||||
|
'Expected feeRate: -1 to be greater than or equal to 0',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('correctly calculates fee adjusted rate when feeRate is provided', async () => {
|
||||||
|
const feeRate = new BigNumber(2); // ZRX costs 2 units of takerAsset per 1 unit of ZRX
|
||||||
|
const feeAdjustedRate = rateUtils.getFeeAdjustedRateOfOrder(testOrder, feeRate);
|
||||||
|
// the order actually takes 100 + (2 * 20) takerAsset units to fill 100 units of makerAsset
|
||||||
|
expect(feeAdjustedRate).to.bignumber.equal(new BigNumber(1.4));
|
||||||
|
});
|
||||||
|
it('correctly calculates fee adjusted rate when no feeRate is provided', async () => {
|
||||||
|
const feeAdjustedRate = rateUtils.getFeeAdjustedRateOfOrder(testOrder);
|
||||||
|
// because no feeRate was provided we just assume 0 fees
|
||||||
|
// the order actually takes 100 takerAsset units to fill 100 units of makerAsset
|
||||||
|
expect(feeAdjustedRate).to.bignumber.equal(new BigNumber(1));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#getFeeAdjustedRateOfFeeOrder', () => {
|
||||||
|
it('throws when takerFee exceeds makerAssetAmount', async () => {
|
||||||
|
const badOrder = testOrderFactory.generateTestSignedOrder({
|
||||||
|
makerAssetAmount: new BigNumber(100),
|
||||||
|
takerFee: new BigNumber(101),
|
||||||
|
});
|
||||||
|
expect(() => rateUtils.getFeeAdjustedRateOfFeeOrder(badOrder)).to.throw(
|
||||||
|
'Expected takerFee: "101" to be less than makerAssetAmount: "100"',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('correctly calculates fee adjusted rate', async () => {
|
||||||
|
const feeAdjustedRate = rateUtils.getFeeAdjustedRateOfFeeOrder(testOrder);
|
||||||
|
// the order actually takes 100 takerAsset units to fill (100 - 20) units of makerAsset
|
||||||
|
expect(feeAdjustedRate).to.bignumber.equal(new BigNumber(1.25));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
67
packages/order-utils/test/sorting_utils_test.ts
Normal file
67
packages/order-utils/test/sorting_utils_test.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { BigNumber } from '@0xproject/utils';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
import 'mocha';
|
||||||
|
|
||||||
|
import { sortingUtils } from '../src';
|
||||||
|
|
||||||
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
|
import { testOrderFactory } from './utils/test_order_factory';
|
||||||
|
|
||||||
|
chaiSetup.configure();
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
describe('sortingUtils', () => {
|
||||||
|
describe('#sortOrdersByFeeAdjustedRate', () => {
|
||||||
|
const feeRate = new BigNumber(1); // ZRX costs 1 unit of takerAsset per 1 unit of ZRX
|
||||||
|
// rate: 2 takerAsset / makerAsset
|
||||||
|
const testOrder1 = testOrderFactory.generateTestSignedOrder({
|
||||||
|
makerAssetAmount: new BigNumber(100),
|
||||||
|
takerAssetAmount: new BigNumber(200),
|
||||||
|
});
|
||||||
|
// rate: 1 takerAsset / makerAsset
|
||||||
|
const testOrder2 = testOrderFactory.generateTestSignedOrder({
|
||||||
|
makerAssetAmount: new BigNumber(100),
|
||||||
|
takerAssetAmount: new BigNumber(100),
|
||||||
|
});
|
||||||
|
// rate: 2.5 takerAsset / makerAsset
|
||||||
|
const testOrder3 = testOrderFactory.generateTestSignedOrder({
|
||||||
|
makerAssetAmount: new BigNumber(100),
|
||||||
|
takerAssetAmount: new BigNumber(200),
|
||||||
|
takerFee: new BigNumber(50),
|
||||||
|
});
|
||||||
|
it('correctly sorts by fee adjusted rate when feeRate is Provided', async () => {
|
||||||
|
const orders = [testOrder1, testOrder2, testOrder3];
|
||||||
|
const sortedOrders = sortingUtils.sortOrdersByFeeAdjustedRate(orders, feeRate);
|
||||||
|
expect(sortedOrders).to.deep.equal([testOrder2, testOrder1, testOrder3]);
|
||||||
|
});
|
||||||
|
it('correctly sorts by fee adjusted rate when no feeRate is Provided', async () => {
|
||||||
|
const orders = [testOrder1, testOrder2, testOrder3];
|
||||||
|
const sortedOrders = sortingUtils.sortOrdersByFeeAdjustedRate(orders);
|
||||||
|
expect(sortedOrders).to.deep.equal([testOrder2, testOrder1, testOrder3]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#sortFeeOrdersByFeeAdjustedRate', () => {
|
||||||
|
// rate: 200 takerAsset / makerAsset
|
||||||
|
const testOrder1 = testOrderFactory.generateTestSignedOrder({
|
||||||
|
makerAssetAmount: new BigNumber(100),
|
||||||
|
takerAssetAmount: new BigNumber(200),
|
||||||
|
takerFee: new BigNumber(99),
|
||||||
|
});
|
||||||
|
// rate: 1 takerAsset / makerAsset
|
||||||
|
const testOrder2 = testOrderFactory.generateTestSignedOrder({
|
||||||
|
makerAssetAmount: new BigNumber(100),
|
||||||
|
takerAssetAmount: new BigNumber(100),
|
||||||
|
});
|
||||||
|
// rate: 4 takerAsset / makerAsset
|
||||||
|
const testOrder3 = testOrderFactory.generateTestSignedOrder({
|
||||||
|
makerAssetAmount: new BigNumber(100),
|
||||||
|
takerAssetAmount: new BigNumber(200),
|
||||||
|
takerFee: new BigNumber(50),
|
||||||
|
});
|
||||||
|
it('correctly sorts by fee adjusted rate', async () => {
|
||||||
|
const orders = [testOrder1, testOrder2, testOrder3];
|
||||||
|
const sortedOrders = sortingUtils.sortFeeOrdersByFeeAdjustedRate(orders);
|
||||||
|
expect(sortedOrders).to.deep.equal([testOrder2, testOrder3, testOrder1]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -55,7 +55,7 @@
|
|||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"chai-bignumber": "^2.0.1",
|
"chai-bignumber": "^2.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
|
@ -501,25 +501,27 @@ describe('OrderWatcher', () => {
|
|||||||
expect(orderState.isValid).to.be.false();
|
expect(orderState.isValid).to.be.false();
|
||||||
const invalidOrderState = orderState as OrderStateInvalid;
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
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);
|
orderWatcher.subscribe(callback);
|
||||||
await contractWrappers.exchange.cancelOrderAsync(signedOrder);
|
await contractWrappers.exchange.cancelOrderAsync(signedOrder);
|
||||||
})().catch(done);
|
})().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 () => {
|
(async () => {
|
||||||
const remainingFillableAmountInBaseUnits = new BigNumber(100);
|
const fillAmountInBaseUnits = new BigNumber(2);
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const makerAssetAmount = new BigNumber(1001);
|
||||||
|
const takerAssetAmount = new BigNumber(3);
|
||||||
|
signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerAssetData,
|
makerAssetData,
|
||||||
takerAssetData,
|
takerAssetData,
|
||||||
makerAddress,
|
makerAddress,
|
||||||
takerAddress,
|
takerAddress,
|
||||||
fillableAmount,
|
makerAssetAmount,
|
||||||
|
takerAssetAmount,
|
||||||
);
|
);
|
||||||
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||||
await orderWatcher.addOrderAsync(signedOrder);
|
await orderWatcher.addOrderAsync(signedOrder);
|
||||||
|
|
||||||
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.false();
|
expect(orderState.isValid).to.be.false();
|
||||||
const invalidOrderState = orderState as OrderStateInvalid;
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
@ -527,11 +529,7 @@ describe('OrderWatcher', () => {
|
|||||||
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError);
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError);
|
||||||
});
|
});
|
||||||
orderWatcher.subscribe(callback);
|
orderWatcher.subscribe(callback);
|
||||||
await contractWrappers.exchange.fillOrderAsync(
|
await contractWrappers.exchange.fillOrderAsync(signedOrder, fillAmountInBaseUnits, takerAddress);
|
||||||
signedOrder,
|
|
||||||
fillableAmount.minus(remainingFillableAmountInBaseUnits),
|
|
||||||
takerAddress,
|
|
||||||
);
|
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
describe('erc721', () => {
|
describe('erc721', () => {
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
"@types/react-dom": "^16.0.3",
|
"@types/react-dom": "^16.0.3",
|
||||||
"@types/react-tap-event-plugin": "0.0.30",
|
"@types/react-tap-event-plugin": "0.0.30",
|
||||||
"awesome-typescript-loader": "^3.1.3",
|
"awesome-typescript-loader": "^3.1.3",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"css-loader": "^0.28.9",
|
"css-loader": "^0.28.9",
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"less": "^2.7.2",
|
"less": "^2.7.2",
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
"@0xproject/monorepo-scripts": "^1.0.5",
|
"@0xproject/monorepo-scripts": "^1.0.5",
|
||||||
"@0xproject/tslint-config": "^1.0.5",
|
"@0xproject/tslint-config": "^1.0.5",
|
||||||
"@types/compare-versions": "^3.0.0",
|
"@types/compare-versions": "^3.0.0",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
"tslint": "^5.9.1",
|
"tslint": "^5.9.1",
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
"@0xproject/dev-utils": "^1.0.4",
|
"@0xproject/dev-utils": "^1.0.4",
|
||||||
"@0xproject/monorepo-scripts": "^1.0.5",
|
"@0xproject/monorepo-scripts": "^1.0.5",
|
||||||
"@0xproject/tslint-config": "^1.0.5",
|
"@0xproject/tslint-config": "^1.0.5",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
"tslint": "^5.9.1",
|
"tslint": "^5.9.1",
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
"@types/semver": "^5.5.0",
|
"@types/semver": "^5.5.0",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^4.1.0",
|
"mocha": "^4.1.0",
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
"@types/rimraf": "^2.0.2",
|
"@types/rimraf": "^2.0.2",
|
||||||
"@types/solidity-parser-antlr": "^0.2.1",
|
"@types/solidity-parser-antlr": "^0.2.1",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^4.1.0",
|
"mocha": "^4.1.0",
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/monorepo-scripts": "^1.0.5",
|
"@0xproject/monorepo-scripts": "^1.0.5",
|
||||||
"@0xproject/tslint-config": "^1.0.5",
|
"@0xproject/tslint-config": "^1.0.5",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
"tslint": "5.11.0",
|
"tslint": "5.11.0",
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
"@types/yargs": "^10.0.0",
|
"@types/yargs": "^10.0.0",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^4.1.0",
|
"mocha": "^4.1.0",
|
||||||
|
@ -74,7 +74,7 @@
|
|||||||
"@types/sinon": "^2.2.2",
|
"@types/sinon": "^2.2.2",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^4.1.0",
|
"mocha": "^4.1.0",
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/monorepo-scripts": "^1.0.5",
|
"@0xproject/monorepo-scripts": "^1.0.5",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/monorepo-scripts": "^1.0.5",
|
"@0xproject/monorepo-scripts": "^1.0.5",
|
||||||
"@0xproject/tslint-config": "^1.0.5",
|
"@0xproject/tslint-config": "^1.0.5",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
"tslint": "5.11.0",
|
"tslint": "5.11.0",
|
||||||
|
@ -62,8 +62,7 @@ export interface ValidatorSignature {
|
|||||||
export enum ExchangeContractErrs {
|
export enum ExchangeContractErrs {
|
||||||
OrderFillExpired = 'ORDER_FILL_EXPIRED',
|
OrderFillExpired = 'ORDER_FILL_EXPIRED',
|
||||||
OrderCancelExpired = 'ORDER_CANCEL_EXPIRED',
|
OrderCancelExpired = 'ORDER_CANCEL_EXPIRED',
|
||||||
OrderCancelAmountZero = 'ORDER_CANCEL_AMOUNT_ZERO',
|
OrderCancelled = 'ORDER_CANCELLED',
|
||||||
OrderAlreadyCancelledOrFilled = 'ORDER_ALREADY_CANCELLED_OR_FILLED',
|
|
||||||
OrderFillAmountZero = 'ORDER_FILL_AMOUNT_ZERO',
|
OrderFillAmountZero = 'ORDER_FILL_AMOUNT_ZERO',
|
||||||
OrderRemainingFillAmountZero = 'ORDER_REMAINING_FILL_AMOUNT_ZERO',
|
OrderRemainingFillAmountZero = 'ORDER_REMAINING_FILL_AMOUNT_ZERO',
|
||||||
OrderFillRoundingError = 'ORDER_FILL_ROUNDING_ERROR',
|
OrderFillRoundingError = 'ORDER_FILL_ROUNDING_ERROR',
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/monorepo-scripts": "^1.0.5",
|
"@0xproject/monorepo-scripts": "^1.0.5",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"shx": "^0.2.2"
|
"shx": "^0.2.2"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
"mocha": "^4.1.0",
|
"mocha": "^4.1.0",
|
||||||
"npm-run-all": "^4.1.2",
|
"npm-run-all": "^4.1.2",
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"chai-bignumber": "^2.0.1",
|
"chai-bignumber": "^2.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"ganache-core": "0xProject/ganache-core#monorepo-dep",
|
"ganache-core": "0xProject/ganache-core#monorepo-dep",
|
||||||
"make-promises-safe": "^1.1.0",
|
"make-promises-safe": "^1.1.0",
|
||||||
|
@ -84,7 +84,7 @@
|
|||||||
"@types/redux": "^3.6.0",
|
"@types/redux": "^3.6.0",
|
||||||
"awesome-typescript-loader": "^3.1.3",
|
"awesome-typescript-loader": "^3.1.3",
|
||||||
"copy-webpack-plugin": "^4.0.1",
|
"copy-webpack-plugin": "^4.0.1",
|
||||||
"copyfiles": "^1.2.0",
|
"copyfiles": "^2.0.0",
|
||||||
"css-loader": "0.23.x",
|
"css-loader": "0.23.x",
|
||||||
"exports-loader": "0.6.x",
|
"exports-loader": "0.6.x",
|
||||||
"imports-loader": "0.6.x",
|
"imports-loader": "0.6.x",
|
||||||
|
@ -247,12 +247,9 @@ export const utils = {
|
|||||||
} = {
|
} = {
|
||||||
[ExchangeContractErrs.OrderFillExpired]: 'This order has expired',
|
[ExchangeContractErrs.OrderFillExpired]: 'This order has expired',
|
||||||
[ExchangeContractErrs.OrderCancelExpired]: 'This order has expired',
|
[ExchangeContractErrs.OrderCancelExpired]: 'This order has expired',
|
||||||
[ExchangeContractErrs.OrderCancelAmountZero]: "Order cancel amount can't be 0",
|
[ExchangeContractErrs.OrderCancelled]: 'This order has been cancelled',
|
||||||
[ExchangeContractErrs.OrderAlreadyCancelledOrFilled]:
|
|
||||||
'This order has already been completely filled or cancelled',
|
|
||||||
[ExchangeContractErrs.OrderFillAmountZero]: "Order fill amount can't be 0",
|
[ExchangeContractErrs.OrderFillAmountZero]: "Order fill amount can't be 0",
|
||||||
[ExchangeContractErrs.OrderRemainingFillAmountZero]:
|
[ExchangeContractErrs.OrderRemainingFillAmountZero]: 'This order has already been completely filled',
|
||||||
'This order has already been completely filled or cancelled',
|
|
||||||
[ExchangeContractErrs.OrderFillRoundingError]:
|
[ExchangeContractErrs.OrderFillRoundingError]:
|
||||||
'Rounding error will occur when filling this order. Please try filling a different amount.',
|
'Rounding error will occur when filling this order. Please try filling a different amount.',
|
||||||
[ExchangeContractErrs.InsufficientTakerBalance]:
|
[ExchangeContractErrs.InsufficientTakerBalance]:
|
||||||
|
45
yarn.lock
45
yarn.lock
@ -944,9 +944,9 @@
|
|||||||
"@types/express-serve-static-core" "*"
|
"@types/express-serve-static-core" "*"
|
||||||
"@types/serve-static" "*"
|
"@types/serve-static" "*"
|
||||||
|
|
||||||
"@types/fetch-mock@^5.12.2":
|
"@types/fetch-mock@^6.0.3":
|
||||||
version "5.12.2"
|
version "6.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/fetch-mock/-/fetch-mock-5.12.2.tgz#8c96517ff74303031c65c5da2d99858e34c844d2"
|
resolved "https://registry.yarnpkg.com/@types/fetch-mock/-/fetch-mock-6.0.3.tgz#54ba90776293e728089bf53ba53e3c69f1c80655"
|
||||||
|
|
||||||
"@types/find-versions@^2.0.0":
|
"@types/find-versions@^2.0.0":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
@ -1371,7 +1371,7 @@ aes-js@3.0.0:
|
|||||||
|
|
||||||
aes-js@^3.1.1:
|
aes-js@^3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.1.1.tgz#89fd1f94ae51b4c72d62466adc1a7323ff52f072"
|
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.1.tgz#89fd1f94ae51b4c72d62466adc1a7323ff52f072"
|
||||||
|
|
||||||
ajv-keywords@^2.1.0:
|
ajv-keywords@^2.1.0:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
@ -2844,7 +2844,7 @@ bs58@^2.0.1:
|
|||||||
|
|
||||||
bs58check@^2.1.2:
|
bs58check@^2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc"
|
resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc"
|
||||||
dependencies:
|
dependencies:
|
||||||
bs58 "^4.0.0"
|
bs58 "^4.0.0"
|
||||||
create-hash "^1.1.0"
|
create-hash "^1.1.0"
|
||||||
@ -3745,8 +3745,8 @@ copy-to-clipboard@^3:
|
|||||||
toggle-selection "^1.0.3"
|
toggle-selection "^1.0.3"
|
||||||
|
|
||||||
copy-webpack-plugin@^4.0.1:
|
copy-webpack-plugin@^4.0.1:
|
||||||
version "4.5.1"
|
version "4.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.5.1.tgz#fc4f68f4add837cc5e13d111b20715793225d29c"
|
resolved "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.5.2.tgz#d53444a8fea2912d806e78937390ddd7e632ee5c"
|
||||||
dependencies:
|
dependencies:
|
||||||
cacache "^10.0.4"
|
cacache "^10.0.4"
|
||||||
find-cache-dir "^1.0.0"
|
find-cache-dir "^1.0.0"
|
||||||
@ -3757,17 +3757,6 @@ copy-webpack-plugin@^4.0.1:
|
|||||||
p-limit "^1.0.0"
|
p-limit "^1.0.0"
|
||||||
serialize-javascript "^1.4.0"
|
serialize-javascript "^1.4.0"
|
||||||
|
|
||||||
copyfiles@^1.2.0:
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-1.2.0.tgz#a8da3ac41aa2220ae29bd3c58b6984294f2c593c"
|
|
||||||
dependencies:
|
|
||||||
glob "^7.0.5"
|
|
||||||
ltcdr "^2.2.1"
|
|
||||||
minimatch "^3.0.3"
|
|
||||||
mkdirp "^0.5.1"
|
|
||||||
noms "0.0.0"
|
|
||||||
through2 "^2.0.1"
|
|
||||||
|
|
||||||
copyfiles@^2.0.0:
|
copyfiles@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.0.0.tgz#bbd78bb78e8fd6db5c67adf54249317b24560f2a"
|
resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.0.0.tgz#bbd78bb78e8fd6db5c67adf54249317b24560f2a"
|
||||||
@ -5256,7 +5245,7 @@ ethereumjs-vm@^2.0.2, ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4:
|
|||||||
|
|
||||||
ethereumjs-wallet@~0.6.0:
|
ethereumjs-wallet@~0.6.0:
|
||||||
version "0.6.2"
|
version "0.6.2"
|
||||||
resolved "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz#67244b6af3e8113b53d709124b25477b64aeccda"
|
resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz#67244b6af3e8113b53d709124b25477b64aeccda"
|
||||||
dependencies:
|
dependencies:
|
||||||
aes-js "^3.1.1"
|
aes-js "^3.1.1"
|
||||||
bs58check "^2.1.2"
|
bs58check "^2.1.2"
|
||||||
@ -5267,9 +5256,9 @@ ethereumjs-wallet@~0.6.0:
|
|||||||
utf8 "^3.0.0"
|
utf8 "^3.0.0"
|
||||||
uuid "^3.3.2"
|
uuid "^3.3.2"
|
||||||
|
|
||||||
ethers@3.0.22:
|
ethers@0xproject/ethers.js#eip-838-reasons, ethers@3.0.22:
|
||||||
version "3.0.22"
|
version "3.0.18"
|
||||||
resolved "https://registry.npmjs.org/ethers/-/ethers-3.0.22.tgz#7fab1ea16521705837aa43c15831877b2716b436"
|
resolved "https://codeload.github.com/0xproject/ethers.js/tar.gz/b91342bd200d142af0165d6befddf783c8ae8447"
|
||||||
dependencies:
|
dependencies:
|
||||||
aes-js "3.0.0"
|
aes-js "3.0.0"
|
||||||
bn.js "^4.4.0"
|
bn.js "^4.4.0"
|
||||||
@ -6693,8 +6682,8 @@ hdkey@^0.7.1:
|
|||||||
secp256k1 "^3.0.1"
|
secp256k1 "^3.0.1"
|
||||||
|
|
||||||
hdkey@^1.0.0:
|
hdkey@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.npmjs.org/hdkey/-/hdkey-1.1.0.tgz#e74e7b01d2c47f797fa65d1d839adb7a44639f29"
|
resolved "https://registry.yarnpkg.com/hdkey/-/hdkey-1.0.0.tgz#1d658dfe966aaa542c1d499586200b325e5c0cf4"
|
||||||
dependencies:
|
dependencies:
|
||||||
coinstring "^2.0.0"
|
coinstring "^2.0.0"
|
||||||
safe-buffer "^5.1.1"
|
safe-buffer "^5.1.1"
|
||||||
@ -8559,10 +8548,6 @@ lru-cache@~2.2.1:
|
|||||||
version "2.2.4"
|
version "2.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d"
|
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d"
|
||||||
|
|
||||||
ltcdr@^2.2.1:
|
|
||||||
version "2.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/ltcdr/-/ltcdr-2.2.1.tgz#5ab87ad1d4c1dab8e8c08bbf037ee0c1902287cf"
|
|
||||||
|
|
||||||
ltgt@^2.1.2, ltgt@~2.2.0:
|
ltgt@^2.1.2, ltgt@~2.2.0:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5"
|
resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5"
|
||||||
@ -14038,7 +14023,7 @@ utf8@^2.1.1:
|
|||||||
|
|
||||||
utf8@^3.0.0:
|
utf8@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
|
resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
|
||||||
|
|
||||||
util-deprecate@~1.0.1:
|
util-deprecate@~1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
@ -14087,7 +14072,7 @@ uuid@^2.0.1:
|
|||||||
|
|
||||||
uuid@^3.3.2:
|
uuid@^3.3.2:
|
||||||
version "3.3.2"
|
version "3.3.2"
|
||||||
resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
||||||
|
|
||||||
uvm@1.7.0:
|
uvm@1.7.0:
|
||||||
version "1.7.0"
|
version "1.7.0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user