Atomic Order Matching - Tests
This commit is contained in:
@@ -8,6 +8,9 @@ export const assetProxyUtils = {
|
||||
encodeAssetProxyId(assetProxyId: AssetProxyId): Buffer {
|
||||
return ethUtil.toBuffer(assetProxyId);
|
||||
},
|
||||
decodeAssetProxyId(encodedAssetProxyId: Buffer): AssetProxyId {
|
||||
return ethUtil.bufferToInt(encodedAssetProxyId);
|
||||
},
|
||||
encodeAddress(address: string): Buffer {
|
||||
if (!ethUtil.isValidAddress(address)) {
|
||||
throw new Error(`Invalid Address: ${address}`);
|
||||
@@ -15,12 +18,24 @@ export const assetProxyUtils = {
|
||||
const encodedAddress = ethUtil.toBuffer(address);
|
||||
return encodedAddress;
|
||||
},
|
||||
decodeAddress(encodedAddress: Buffer): string {
|
||||
const address = ethUtil.bufferToHex(encodedAddress);
|
||||
if (!ethUtil.isValidAddress(address)) {
|
||||
throw new Error(`Invalid Address: ${address}`);
|
||||
}
|
||||
return address;
|
||||
},
|
||||
encodeUint256(value: BigNumber): Buffer {
|
||||
const formattedValue = new BN(value.toString(10));
|
||||
const encodedValue = ethUtil.toBuffer(formattedValue);
|
||||
const paddedValue = ethUtil.setLengthLeft(encodedValue, 32);
|
||||
return paddedValue;
|
||||
},
|
||||
decodeUint256(encodedValue: Buffer): BigNumber {
|
||||
const formattedValue = ethUtil.bufferToHex(encodedValue);
|
||||
const value = new BigNumber(formattedValue, 16);
|
||||
return value;
|
||||
},
|
||||
encodeERC20ProxyData(tokenAddress: string): string {
|
||||
const encodedAssetProxyId = assetProxyUtils.encodeAssetProxyId(AssetProxyId.ERC20);
|
||||
const encodedAddress = assetProxyUtils.encodeAddress(tokenAddress);
|
||||
@@ -28,6 +43,28 @@ export const assetProxyUtils = {
|
||||
const encodedMetadataHex = ethUtil.bufferToHex(encodedMetadata);
|
||||
return encodedMetadataHex;
|
||||
},
|
||||
decodeERC20ProxyData(proxyData: string): string /* tokenAddress */ {
|
||||
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
|
||||
if (encodedProxyMetadata.byteLength !== 21) {
|
||||
throw new Error(
|
||||
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be 21. Got ${
|
||||
encodedProxyMetadata.byteLength
|
||||
}`,
|
||||
);
|
||||
}
|
||||
const encodedAssetProxyId = encodedProxyMetadata.slice(0, 1);
|
||||
const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId);
|
||||
if (assetProxyId !== AssetProxyId.ERC20) {
|
||||
throw new Error(
|
||||
`Could not decode ERC20 Proxy Data. Expected Asset Proxy Id to be ERC20 (${
|
||||
AssetProxyId.ERC20
|
||||
}), but got ${assetProxyId}`,
|
||||
);
|
||||
}
|
||||
const encodedTokenAddress = encodedProxyMetadata.slice(1, 21);
|
||||
const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress);
|
||||
return tokenAddress;
|
||||
},
|
||||
encodeERC721ProxyData(tokenAddress: string, tokenId: BigNumber): string {
|
||||
const encodedAssetProxyId = assetProxyUtils.encodeAssetProxyId(AssetProxyId.ERC721);
|
||||
const encodedAddress = assetProxyUtils.encodeAddress(tokenAddress);
|
||||
@@ -36,4 +73,41 @@ export const assetProxyUtils = {
|
||||
const encodedMetadataHex = ethUtil.bufferToHex(encodedMetadata);
|
||||
return encodedMetadataHex;
|
||||
},
|
||||
decodeERC721ProxyData(proxyData: string): [string /* tokenAddress */, BigNumber /* tokenId */] {
|
||||
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
|
||||
if (encodedProxyMetadata.byteLength !== 53) {
|
||||
throw new Error(
|
||||
`Could not decode ERC20 Proxy Data. Expected length of encoded data to be 53. Got ${
|
||||
encodedProxyMetadata.byteLength
|
||||
}`,
|
||||
);
|
||||
}
|
||||
const encodedAssetProxyId = encodedProxyMetadata.slice(0, 1);
|
||||
const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId);
|
||||
if (assetProxyId !== AssetProxyId.ERC721) {
|
||||
throw new Error(
|
||||
`Could not decode ERC721 Proxy Data. Expected Asset Proxy Id to be ERC721 (${
|
||||
AssetProxyId.ERC721
|
||||
}), but got ${assetProxyId}`,
|
||||
);
|
||||
}
|
||||
const encodedTokenAddress = encodedProxyMetadata.slice(1, 21);
|
||||
const tokenAddress = assetProxyUtils.decodeAddress(encodedTokenAddress);
|
||||
const encodedTokenId = encodedProxyMetadata.slice(21, 53);
|
||||
const tokenId = assetProxyUtils.decodeUint256(encodedTokenId);
|
||||
return [tokenAddress, tokenId];
|
||||
},
|
||||
decodeProxyDataId(proxyData: string): AssetProxyId {
|
||||
const encodedProxyMetadata = ethUtil.toBuffer(proxyData);
|
||||
if (encodedProxyMetadata.byteLength < 1) {
|
||||
throw new Error(
|
||||
`Could not decode Proxy Data. Expected length of encoded data to be at least 1. Got ${
|
||||
encodedProxyMetadata.byteLength
|
||||
}`,
|
||||
);
|
||||
}
|
||||
const encodedAssetProxyId = encodedProxyMetadata.slice(0, 1);
|
||||
const assetProxyId = assetProxyUtils.decodeAssetProxyId(encodedAssetProxyId);
|
||||
return assetProxyId;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -231,4 +231,26 @@ export class ExchangeWrapper {
|
||||
tx.logs = _.map(tx.logs, log => this._logDecoder.decodeLogOrThrow(log));
|
||||
return tx;
|
||||
}
|
||||
public async getOrderInfoAsync(
|
||||
signedOrder: SignedOrder,
|
||||
): Promise<[number /* orderStatus */, string /* orderHash */, BigNumber /* orderTakerAssetAmountFilled */]> {
|
||||
const orderInfo: [number, string, BigNumber] = await this._exchange.getOrderInfo.callAsync(signedOrder);
|
||||
return orderInfo;
|
||||
}
|
||||
public async matchOrdersAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
from: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||
const txHash = await this._exchange.matchOrders.sendTransactionAsync(
|
||||
params.left,
|
||||
params.right,
|
||||
params.leftSignature,
|
||||
params.rightSignature,
|
||||
{ from },
|
||||
);
|
||||
const tx = await this._getTxWithDecodedExchangeLogsAsync(txHash);
|
||||
return tx;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,4 +80,13 @@ export const orderUtils = {
|
||||
const orderHashHex = `0x${orderHashBuff.toString('hex')}`;
|
||||
return orderHashHex;
|
||||
},
|
||||
createMatchOrders(signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder) {
|
||||
const fill = {
|
||||
left: orderUtils.getOrderStruct(signedOrderLeft),
|
||||
right: orderUtils.getOrderStruct(signedOrderRight),
|
||||
leftSignature: signedOrderLeft.signature,
|
||||
rightSignature: signedOrderRight.signature,
|
||||
};
|
||||
return fill;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -74,12 +74,27 @@ export interface Token {
|
||||
swarmHash: string;
|
||||
}
|
||||
|
||||
export enum ExchangeContractErrs {
|
||||
ERROR_ORDER_EXPIRED,
|
||||
ERROR_ORDER_FULLY_FILLED,
|
||||
ERROR_ORDER_CANCELLED,
|
||||
ERROR_ROUNDING_ERROR_TOO_LARGE,
|
||||
ERROR_INSUFFICIENT_BALANCE_OR_ALLOWANCE,
|
||||
export enum ExchangeStatus {
|
||||
/// Default Status ///
|
||||
INVALID, // General invalid status
|
||||
|
||||
/// General Exchange Statuses ///
|
||||
SUCCESS, // Indicates a successful operation
|
||||
ROUNDING_ERROR_TOO_LARGE, // Rounding error too large
|
||||
INSUFFICIENT_BALANCE_OR_ALLOWANCE, // Insufficient balance or allowance for token transfer
|
||||
TAKER_ASSET_FILL_AMOUNT_TOO_LOW, // takerAssetFillAmount is <= 0
|
||||
INVALID_SIGNATURE, // Invalid signature
|
||||
INVALID_SENDER, // Invalid sender
|
||||
INVALID_TAKER, // Invalid taker
|
||||
INVALID_MAKER, // Invalid maker
|
||||
|
||||
/// Order State Statuses ///
|
||||
ORDER_INVALID_MAKER_ASSET_AMOUNT, // Order does not have a valid maker asset amount
|
||||
ORDER_INVALID_TAKER_ASSET_AMOUNT, // Order does not have a valid taker asset amount
|
||||
ORDER_FILLABLE, // Order is fillable
|
||||
ORDER_EXPIRED, // Order has already expired
|
||||
ORDER_FULLY_FILLED, // Order is fully filled
|
||||
ORDER_CANCELLED, // Order has been cancelled
|
||||
}
|
||||
|
||||
export enum ContractName {
|
||||
@@ -143,3 +158,24 @@ export interface SignedTransaction {
|
||||
data: string;
|
||||
signature: string;
|
||||
}
|
||||
|
||||
export interface TransferAmountsByMatchOrders {
|
||||
// Left Maker
|
||||
amountBoughtByLeftMaker: BigNumber;
|
||||
amountSoldByLeftMaker: BigNumber;
|
||||
amountReceivedByLeftMaker: BigNumber;
|
||||
feePaidByLeftMaker: BigNumber;
|
||||
// Right Maker
|
||||
amountBoughtByRightMaker: BigNumber;
|
||||
amountSoldByRightMaker: BigNumber;
|
||||
amountReceivedByRightMaker: BigNumber;
|
||||
feePaidByRightMaker: BigNumber;
|
||||
// Taker
|
||||
amountReceivedByTaker: BigNumber;
|
||||
feePaidByTakerLeft: BigNumber;
|
||||
feePaidByTakerRight: BigNumber;
|
||||
totalFeePaidByTaker: BigNumber;
|
||||
// Fee Recipients
|
||||
feeReceivedLeft: BigNumber;
|
||||
feeReceivedRight: BigNumber;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c
|
||||
import {
|
||||
CancelContractEventArgs,
|
||||
ExchangeContract,
|
||||
ExchangeErrorContractEventArgs,
|
||||
ExchangeStatusContractEventArgs,
|
||||
FillContractEventArgs,
|
||||
} from '../../src/contract_wrappers/generated/exchange';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
@@ -25,8 +25,8 @@ import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
||||
import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
||||
import { OrderFactory } from '../../src/utils/order_factory';
|
||||
import { orderUtils } from '../../src/utils/order_utils';
|
||||
import { AssetProxyId, ERC20BalancesByOwner, ExchangeContractErrs, SignedOrder } from '../../src/utils/types';
|
||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||
import { AssetProxyId, ContractName, ERC20BalancesByOwner, ExchangeStatus, SignedOrder } from '../../src/utils/types';
|
||||
import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
@@ -556,9 +556,9 @@ describe('Exchange core', () => {
|
||||
|
||||
const res = await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
|
||||
expect(res.logs).to.have.length(1);
|
||||
const log = res.logs[0] as LogWithDecodedArgs<ExchangeErrorContractEventArgs>;
|
||||
const errCode = log.args.errorId;
|
||||
expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_EXPIRED);
|
||||
const log = res.logs[0] as LogWithDecodedArgs<ExchangeStatusContractEventArgs>;
|
||||
const statusCode = log.args.statusId;
|
||||
expect(statusCode).to.be.equal(ExchangeStatus.ORDER_EXPIRED);
|
||||
});
|
||||
|
||||
it('should log an error event if no value is filled', async () => {
|
||||
@@ -567,9 +567,9 @@ describe('Exchange core', () => {
|
||||
|
||||
const res = await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
|
||||
expect(res.logs).to.have.length(1);
|
||||
const log = res.logs[0] as LogWithDecodedArgs<ExchangeErrorContractEventArgs>;
|
||||
const errCode = log.args.errorId;
|
||||
expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_FULLY_FILLED);
|
||||
const log = res.logs[0] as LogWithDecodedArgs<ExchangeStatusContractEventArgs>;
|
||||
const statusCode = log.args.statusId;
|
||||
expect(statusCode).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -635,9 +635,9 @@ describe('Exchange core', () => {
|
||||
|
||||
const res = await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
|
||||
expect(res.logs).to.have.length(1);
|
||||
const log = res.logs[0] as LogWithDecodedArgs<ExchangeErrorContractEventArgs>;
|
||||
const errCode = log.args.errorId;
|
||||
expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_CANCELLED);
|
||||
const log = res.logs[0] as LogWithDecodedArgs<ExchangeStatusContractEventArgs>;
|
||||
const statusCode = log.args.statusId;
|
||||
expect(statusCode).to.be.equal(ExchangeStatus.ORDER_CANCELLED);
|
||||
});
|
||||
|
||||
it('should log error if order is expired', async () => {
|
||||
@@ -647,9 +647,9 @@ describe('Exchange core', () => {
|
||||
|
||||
const res = await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
|
||||
expect(res.logs).to.have.length(1);
|
||||
const log = res.logs[0] as LogWithDecodedArgs<ExchangeErrorContractEventArgs>;
|
||||
const errCode = log.args.errorId;
|
||||
expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_EXPIRED);
|
||||
const log = res.logs[0] as LogWithDecodedArgs<ExchangeStatusContractEventArgs>;
|
||||
const statusCode = log.args.statusId;
|
||||
expect(statusCode).to.be.equal(ExchangeStatus.ORDER_EXPIRED);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
873
packages/contracts/test/exchange/match_orders.ts
Normal file
873
packages/contracts/test/exchange/match_orders.ts
Normal file
@@ -0,0 +1,873 @@
|
||||
import { LogWithDecodedArgs, ZeroEx } from '0x.js';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c20_token';
|
||||
import { DummyERC721TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
|
||||
import {
|
||||
CancelContractEventArgs,
|
||||
ExchangeContract,
|
||||
ExchangeStatusContractEventArgs,
|
||||
FillContractEventArgs,
|
||||
} from '../../src/contract_wrappers/generated/exchange';
|
||||
import { assetProxyUtils } from '../../src/utils/asset_proxy_utils';
|
||||
import { constants } from '../../src/utils/constants';
|
||||
import { crypto } from '../../src/utils/crypto';
|
||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
||||
import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
||||
import { OrderFactory } from '../../src/utils/order_factory';
|
||||
import { orderUtils } from '../../src/utils/order_utils';
|
||||
import {
|
||||
AssetProxyId,
|
||||
ContractName,
|
||||
ERC20BalancesByOwner,
|
||||
ERC721TokenIdsByOwner,
|
||||
ExchangeStatus,
|
||||
SignedOrder,
|
||||
} from '../../src/utils/types';
|
||||
import { chaiSetup } from '../utils/chai_setup';
|
||||
import { deployer } from '../utils/deployer';
|
||||
import { provider, web3Wrapper } from '../utils/web3_wrapper';
|
||||
|
||||
import { MatchOrderTester } from '../utils/match_order_tester';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('matchOrdersAndVerifyBalancesAsync', () => {
|
||||
let makerAddressLeft: string;
|
||||
let makerAddressRight: string;
|
||||
let owner: string;
|
||||
let takerAddress: string;
|
||||
let feeRecipientAddressLeft: string;
|
||||
let feeRecipientAddressRight: string;
|
||||
|
||||
let erc20TokenA: DummyERC20TokenContract;
|
||||
let erc20TokenB: DummyERC20TokenContract;
|
||||
let zrxToken: DummyERC20TokenContract;
|
||||
let erc721Token: DummyERC721TokenContract;
|
||||
let exchange: ExchangeContract;
|
||||
let erc20Proxy: ERC20ProxyContract;
|
||||
let erc721Proxy: ERC721ProxyContract;
|
||||
|
||||
let erc20BalancesByOwner: ERC20BalancesByOwner;
|
||||
let erc721TokenIdsByOwner: ERC721TokenIdsByOwner;
|
||||
let exchangeWrapper: ExchangeWrapper;
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
let erc721Wrapper: ERC721Wrapper;
|
||||
let orderFactoryLeft: OrderFactory;
|
||||
let orderFactoryRight: OrderFactory;
|
||||
|
||||
let erc721LeftMakerAssetIds: BigNumber[];
|
||||
let erc721RightMakerAssetIds: BigNumber[];
|
||||
let erc721TakerAssetIds: BigNumber[];
|
||||
|
||||
let defaultERC20MakerAssetAddress: string;
|
||||
let defaultERC20TakerAssetAddress: string;
|
||||
let defaultERC721AssetAddress: string;
|
||||
|
||||
let matchOrderTester: MatchOrderTester;
|
||||
|
||||
let zeroEx: ZeroEx;
|
||||
|
||||
before(async () => {
|
||||
// Create accounts
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
const usedAddresses = ([
|
||||
owner,
|
||||
makerAddressLeft,
|
||||
makerAddressRight,
|
||||
takerAddress,
|
||||
feeRecipientAddressLeft,
|
||||
feeRecipientAddressRight,
|
||||
] = accounts);
|
||||
// Create wrappers
|
||||
erc20Wrapper = new ERC20Wrapper(deployer, provider, usedAddresses, owner);
|
||||
erc721Wrapper = new ERC721Wrapper(deployer, provider, usedAddresses, owner);
|
||||
// Deploy ERC20 token & ERC20 proxy
|
||||
[erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync();
|
||||
erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||
// Deploy ERC721 token and proxy
|
||||
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
|
||||
erc721Proxy = await erc721Wrapper.deployProxyAsync();
|
||||
await erc721Wrapper.setBalancesAndAllowancesAsync();
|
||||
const erc721Balances = await erc721Wrapper.getBalancesAsync();
|
||||
erc721LeftMakerAssetIds = erc721Balances[makerAddressLeft][erc721Token.address];
|
||||
erc721RightMakerAssetIds = erc721Balances[makerAddressRight][erc721Token.address];
|
||||
erc721TakerAssetIds = erc721Balances[takerAddress][erc721Token.address];
|
||||
// Depoy exchange
|
||||
const exchangeInstance = await deployer.deployAsync(ContractName.Exchange, [
|
||||
assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
]);
|
||||
exchange = new ExchangeContract(exchangeInstance.abi, exchangeInstance.address, provider);
|
||||
zeroEx = new ZeroEx(provider, {
|
||||
exchangeContractAddress: exchange.address,
|
||||
networkId: constants.TESTRPC_NETWORK_ID,
|
||||
});
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, zeroEx);
|
||||
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC721, erc721Proxy.address, owner);
|
||||
// Authorize ERC20 and ERC721 trades by exchange
|
||||
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
|
||||
from: owner,
|
||||
});
|
||||
await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
|
||||
from: owner,
|
||||
});
|
||||
// Set default addresses
|
||||
defaultERC20MakerAssetAddress = erc20TokenA.address;
|
||||
defaultERC20TakerAssetAddress = erc20TokenB.address;
|
||||
defaultERC721AssetAddress = erc721Token.address;
|
||||
// Create default order parameters
|
||||
const defaultOrderParams = {
|
||||
...constants.STATIC_ORDER_PARAMS,
|
||||
exchangeAddress: exchange.address,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
};
|
||||
const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
|
||||
orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParams);
|
||||
const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
|
||||
orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParams);
|
||||
// Set match order tester
|
||||
matchOrderTester = new MatchOrderTester(exchangeWrapper, erc20Wrapper, erc721Wrapper);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('matchOrders', () => {
|
||||
beforeEach(async () => {
|
||||
erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync();
|
||||
erc721TokenIdsByOwner = await erc721Wrapper.getBalancesAsync();
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when orders completely fill each other', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderRight,
|
||||
);
|
||||
expect(rightOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Store original taker balance
|
||||
const takerInitialBalances = _.cloneDeep(erc20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress]);
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
let newERC20BalancesByOwner: ERC20BalancesByOwner;
|
||||
let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
|
||||
[
|
||||
newERC20BalancesByOwner,
|
||||
newERC721TokenIdsByOwner,
|
||||
] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderRight,
|
||||
);
|
||||
expect(rightOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
// Verify taker did not take a profit
|
||||
expect(takerInitialBalances).to.be.deep.equal(
|
||||
newERC20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress],
|
||||
);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when left order is completely filled and right order is partially filled', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(20), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(4), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
// Verify right order was partially filled
|
||||
const rightOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderRight,
|
||||
);
|
||||
expect(rightOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FILLABLE);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when right order is completely filled and left order is partially filled', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
// Verify left order was partially filled
|
||||
const leftOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FILLABLE);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderRight,
|
||||
);
|
||||
expect(rightOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when consecutive calls are used to completely fill the left order', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
let newERC20BalancesByOwner: ERC20BalancesByOwner;
|
||||
let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
|
||||
[
|
||||
newERC20BalancesByOwner,
|
||||
newERC721TokenIdsByOwner,
|
||||
] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
// Verify left order was partially filled
|
||||
const leftOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FILLABLE);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderRight,
|
||||
);
|
||||
expect(rightOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
// Construct second right order
|
||||
// Note: This order needs makerAssetAmount=90/takerAssetAmount=[anything <= 45] to fully fill the right order.
|
||||
// However, we use 100/50 to ensure a partial fill as we want to go down the "left fill"
|
||||
// branch in the contract twice for this test.
|
||||
const signedOrderRight2 = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match signedOrderLeft with signedOrderRight2
|
||||
const leftTakerAssetFilledAmount = signedOrderRight.makerAssetAmount;
|
||||
const rightTakerAssetFilledAmount = new BigNumber(0);
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight2,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
newERC20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
leftTakerAssetFilledAmount,
|
||||
rightTakerAssetFilledAmount,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo2: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderLeft,
|
||||
);
|
||||
expect(leftOrderInfo2[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
// Verify second right order was partially filled
|
||||
const rightOrderInfo2: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderRight2,
|
||||
);
|
||||
expect(rightOrderInfo2[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FILLABLE);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts when consecutive calls are used to completely fill the right order', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
let newERC20BalancesByOwner: ERC20BalancesByOwner;
|
||||
let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
|
||||
[
|
||||
newERC20BalancesByOwner,
|
||||
newERC721TokenIdsByOwner,
|
||||
] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
// Verify left order was partially filled
|
||||
const leftOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderRight,
|
||||
);
|
||||
expect(rightOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FILLABLE);
|
||||
// Create second left order
|
||||
// Note: This order needs makerAssetAmount=96/takerAssetAmount=48 to fully fill the right order.
|
||||
// However, we use 100/50 to ensure a partial fill as we want to go down the "right fill"
|
||||
// branch in the contract twice for this test.
|
||||
const signedOrderLeft2 = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
// Match signedOrderLeft2 with signedOrderRight
|
||||
const leftTakerAssetFilledAmount = new BigNumber(0);
|
||||
const takerAmountReceived = newERC20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress].minus(
|
||||
erc20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress],
|
||||
);
|
||||
const rightTakerAssetFilledAmount = signedOrderLeft.makerAssetAmount.minus(takerAmountReceived);
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft2,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
newERC20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
leftTakerAssetFilledAmount,
|
||||
rightTakerAssetFilledAmount,
|
||||
);
|
||||
// Verify second left order was partially filled
|
||||
const leftOrderInfo2: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderLeft2,
|
||||
);
|
||||
expect(leftOrderInfo2[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FILLABLE);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo2: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderRight,
|
||||
);
|
||||
expect(rightOrderInfo2[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => {
|
||||
const feeRecipientAddress = feeRecipientAddressLeft;
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress,
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts if taker is also the left order maker', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
takerAddress = signedOrderLeft.makerAddress;
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts if taker is also the right order maker', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
takerAddress = signedOrderRight.makerAddress;
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts if taker is also the left fee recipient', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
takerAddress = feeRecipientAddressLeft;
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts if taker is also the right fee recipient', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
takerAddress = feeRecipientAddressRight;
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
});
|
||||
|
||||
it('should transfer the correct amounts if left maker is the left fee recipient and right maker is the right fee recipient', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: makerAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: makerAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
});
|
||||
|
||||
it('Should not transfer any amounts if left order is not fillable', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Cancel left order
|
||||
await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress);
|
||||
// Match orders
|
||||
await exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress);
|
||||
// Verify balances did not change
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(newBalances).to.be.deep.equal(erc20BalancesByOwner);
|
||||
});
|
||||
|
||||
it('Should not transfer any amounts if right order is not fillable', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Cancel right order
|
||||
await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress);
|
||||
// Match orders
|
||||
await exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress);
|
||||
// Verify balances did not change
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(newBalances).to.be.deep.equal(erc20BalancesByOwner);
|
||||
});
|
||||
|
||||
it('should throw if there is not a positive spread', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(1), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
return expect(
|
||||
matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
});
|
||||
|
||||
it('should throw if the left maker asset is not equal to the right taker asset ', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
return expect(
|
||||
matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
});
|
||||
|
||||
it('should throw if the right maker asset is not equal to the left taker asset', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
return expect(
|
||||
matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
});
|
||||
|
||||
it('should transfer correct amounts when left order maker asset is an ERC721 token', async () => {
|
||||
// Create orders to match
|
||||
const erc721TokenToTransfer = erc721LeftMakerAssetIds[0];
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderRight,
|
||||
);
|
||||
expect(rightOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
});
|
||||
|
||||
it('should transfer correct amounts when right order maker asset is an ERC721 token', async () => {
|
||||
// Create orders to match
|
||||
const erc721TokenToTransfer = erc721RightMakerAssetIds[0];
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
makerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: ZeroEx.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
await matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
zrxToken.address,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
);
|
||||
// Verify left order was fully filled
|
||||
const leftOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft);
|
||||
expect(leftOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
// Verify right order was fully filled
|
||||
const rightOrderInfo: [number, string, BigNumber] = await exchangeWrapper.getOrderInfoAsync(
|
||||
signedOrderRight,
|
||||
);
|
||||
expect(rightOrderInfo[0] as ExchangeStatus).to.be.equal(ExchangeStatus.ORDER_FULLY_FILLED);
|
||||
});
|
||||
});
|
||||
}); // tslint:disable-line:max-file-line-count
|
||||
@@ -21,7 +21,7 @@ import { TransactionFactory } from '../../src/utils/transaction_factory';
|
||||
import {
|
||||
AssetProxyId,
|
||||
ERC20BalancesByOwner,
|
||||
ExchangeContractErrs,
|
||||
ExchangeStatus,
|
||||
OrderStruct,
|
||||
SignatureType,
|
||||
SignedOrder,
|
||||
@@ -197,7 +197,7 @@ describe('Exchange transactions', () => {
|
||||
|
||||
it('should cancel the order when signed by maker and called by sender', async () => {
|
||||
await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
|
||||
const res = await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
|
||||
const res = await exchangeWrapper.fillOrderAsync(signedOrder, senderAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(newBalances).to.deep.equal(erc20Balances);
|
||||
});
|
||||
|
||||
353
packages/contracts/test/utils/match_order_tester.ts
Normal file
353
packages/contracts/test/utils/match_order_tester.ts
Normal file
@@ -0,0 +1,353 @@
|
||||
import { LogWithDecodedArgs, ZeroEx } from '0x.js';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c20_token';
|
||||
import { DummyERC721TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
|
||||
import {
|
||||
CancelContractEventArgs,
|
||||
ExchangeContract,
|
||||
FillContractEventArgs,
|
||||
} from '../../src/contract_wrappers/generated/exchange';
|
||||
import { assetProxyUtils } from '../../src/utils/asset_proxy_utils';
|
||||
import { constants } from '../../src/utils/constants';
|
||||
import { crypto } from '../../src/utils/crypto';
|
||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
||||
import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
||||
import { OrderFactory } from '../../src/utils/order_factory';
|
||||
import { orderUtils } from '../../src/utils/order_utils';
|
||||
import {
|
||||
AssetProxyId,
|
||||
ContractName,
|
||||
ERC20BalancesByOwner,
|
||||
ERC721TokenIdsByOwner,
|
||||
ExchangeStatus,
|
||||
SignedOrder,
|
||||
TransferAmountsByMatchOrders as TransferAmounts,
|
||||
} from '../../src/utils/types';
|
||||
import { chaiSetup } from '../utils/chai_setup';
|
||||
import { deployer } from '../utils/deployer';
|
||||
import { provider, web3Wrapper } from '../utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
export class MatchOrderTester {
|
||||
private _exchangeWrapper: ExchangeWrapper;
|
||||
private _erc20Wrapper: ERC20Wrapper;
|
||||
private _erc721Wrapper: ERC721Wrapper;
|
||||
|
||||
/// @dev Calculates the expected balances of order makers, fee recipients, and the taker,
|
||||
/// as a result of matching two orders.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param feeTokenAddress Address of ERC20 fee token.
|
||||
/// @param takerAddress Address of taker (the address who matched the two orders)
|
||||
/// @param erc20BalancesByOwner Current ERC20 balances.
|
||||
/// @param erc721TokenIdsByOwner Current ERC721 token owners.
|
||||
/// @param expectedTransferAmounts A struct containing the expected transfer amounts.
|
||||
/// @return Expected ERC20 balances & ERC721 token owners after orders have been matched.
|
||||
private static _calculateExpectedBalances(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
feeTokenAddress: string,
|
||||
takerAddress: string,
|
||||
erc20BalancesByOwner: ERC20BalancesByOwner,
|
||||
erc721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
expectedTransferAmounts: TransferAmounts,
|
||||
): [ERC20BalancesByOwner, ERC721TokenIdsByOwner] {
|
||||
const makerAddressLeft = signedOrderLeft.makerAddress;
|
||||
const makerAddressRight = signedOrderRight.makerAddress;
|
||||
const feeRecipientAddressLeft = signedOrderLeft.feeRecipientAddress;
|
||||
const feeRecipientAddressRight = signedOrderRight.feeRecipientAddress;
|
||||
// Operations are performed on copies of the balances
|
||||
const expectedNewERC20BalancesByOwner = _.cloneDeep(erc20BalancesByOwner);
|
||||
const expectedNewERC721TokenIdsByOwner = _.cloneDeep(erc721TokenIdsByOwner);
|
||||
// Left Maker Asset (Right Taker Asset)
|
||||
const makerAssetProxyIdLeft = assetProxyUtils.decodeProxyDataId(signedOrderLeft.makerAssetData);
|
||||
if (makerAssetProxyIdLeft === AssetProxyId.ERC20) {
|
||||
// Decode asset data
|
||||
const makerAssetAddressLeft = assetProxyUtils.decodeERC20ProxyData(signedOrderLeft.makerAssetData);
|
||||
const takerAssetAddressRight = makerAssetAddressLeft;
|
||||
// Left Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressLeft][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
|
||||
makerAddressLeft
|
||||
][makerAssetAddressLeft].minus(expectedTransferAmounts.amountSoldByLeftMaker);
|
||||
// Right Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressRight][
|
||||
takerAssetAddressRight
|
||||
] = expectedNewERC20BalancesByOwner[makerAddressRight][takerAssetAddressRight].add(
|
||||
expectedTransferAmounts.amountReceivedByRightMaker,
|
||||
);
|
||||
// Taker
|
||||
expectedNewERC20BalancesByOwner[takerAddress][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
|
||||
takerAddress
|
||||
][makerAssetAddressLeft].add(expectedTransferAmounts.amountReceivedByTaker);
|
||||
} else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) {
|
||||
// Decode asset data
|
||||
let makerAssetAddressLeft;
|
||||
let makerAssetIdLeft;
|
||||
[makerAssetAddressLeft, makerAssetIdLeft] = assetProxyUtils.decodeERC721ProxyData(
|
||||
signedOrderLeft.makerAssetData,
|
||||
);
|
||||
const takerAssetAddressRight = makerAssetAddressLeft;
|
||||
const takerAssetIdRight = makerAssetIdLeft;
|
||||
// Left Maker
|
||||
_.remove(expectedNewERC721TokenIdsByOwner[makerAddressLeft][makerAssetAddressLeft], makerAssetIdLeft);
|
||||
// Right Maker
|
||||
expectedNewERC721TokenIdsByOwner[makerAddressRight][takerAssetAddressRight].push(takerAssetIdRight);
|
||||
// Taker: Since there is only 1 asset transferred, the taker does not receive any of the left maker asset.
|
||||
}
|
||||
// Left Taker Asset (Right Maker Asset)
|
||||
// Note: This exchange is only between the order makers: the Taker does not receive any of the left taker asset.
|
||||
const takerAssetProxyIdLeft = assetProxyUtils.decodeProxyDataId(signedOrderLeft.takerAssetData);
|
||||
if (takerAssetProxyIdLeft === AssetProxyId.ERC20) {
|
||||
// Decode asset data
|
||||
const takerAssetAddressLeft = assetProxyUtils.decodeERC20ProxyData(signedOrderLeft.takerAssetData);
|
||||
const makerAssetAddressRight = takerAssetAddressLeft;
|
||||
// Left Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressLeft][takerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
|
||||
makerAddressLeft
|
||||
][takerAssetAddressLeft].add(expectedTransferAmounts.amountReceivedByLeftMaker);
|
||||
// Right Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressRight][
|
||||
makerAssetAddressRight
|
||||
] = expectedNewERC20BalancesByOwner[makerAddressRight][makerAssetAddressRight].minus(
|
||||
expectedTransferAmounts.amountSoldByRightMaker,
|
||||
);
|
||||
} else if (takerAssetProxyIdLeft === AssetProxyId.ERC721) {
|
||||
// Decode asset data
|
||||
let makerAssetAddressRight;
|
||||
let makerAssetIdRight;
|
||||
[makerAssetAddressRight, makerAssetIdRight] = assetProxyUtils.decodeERC721ProxyData(
|
||||
signedOrderRight.makerAssetData,
|
||||
);
|
||||
const takerAssetAddressLeft = makerAssetAddressRight;
|
||||
const takerAssetIdLeft = makerAssetIdRight;
|
||||
// Right Maker
|
||||
_.remove(expectedNewERC721TokenIdsByOwner[makerAddressRight][makerAssetAddressRight], makerAssetIdRight);
|
||||
// Left Maker
|
||||
expectedNewERC721TokenIdsByOwner[makerAddressLeft][takerAssetAddressLeft].push(takerAssetIdLeft);
|
||||
}
|
||||
// Left Maker Fees
|
||||
expectedNewERC20BalancesByOwner[makerAddressLeft][feeTokenAddress] = expectedNewERC20BalancesByOwner[
|
||||
makerAddressLeft
|
||||
][feeTokenAddress].minus(expectedTransferAmounts.feePaidByLeftMaker);
|
||||
// Right Maker Fees
|
||||
expectedNewERC20BalancesByOwner[makerAddressRight][feeTokenAddress] = expectedNewERC20BalancesByOwner[
|
||||
makerAddressRight
|
||||
][feeTokenAddress].minus(expectedTransferAmounts.feePaidByRightMaker);
|
||||
// Taker Fees
|
||||
expectedNewERC20BalancesByOwner[takerAddress][feeTokenAddress] = expectedNewERC20BalancesByOwner[takerAddress][
|
||||
feeTokenAddress
|
||||
].minus(expectedTransferAmounts.totalFeePaidByTaker);
|
||||
// Left Fee Recipient Fees
|
||||
expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][feeTokenAddress] = expectedNewERC20BalancesByOwner[
|
||||
feeRecipientAddressLeft
|
||||
][feeTokenAddress].add(expectedTransferAmounts.feeReceivedLeft);
|
||||
// Right Fee Recipient Fees
|
||||
expectedNewERC20BalancesByOwner[feeRecipientAddressRight][feeTokenAddress] = expectedNewERC20BalancesByOwner[
|
||||
feeRecipientAddressRight
|
||||
][feeTokenAddress].add(expectedTransferAmounts.feeReceivedRight);
|
||||
|
||||
return [expectedNewERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner];
|
||||
}
|
||||
|
||||
/// @dev Compares a pair of ERC20 balances and a pair of ERC721 token owners.
|
||||
/// @param expectedNewERC20BalancesByOwner Expected ERC20 balances.
|
||||
/// @param realERC20BalancesByOwner Actual ERC20 balances.
|
||||
/// @param expectedNewERC721TokenIdsByOwner Expected ERC721 token owners.
|
||||
/// @param realERC721TokenIdsByOwner Actual ERC20 token owners.
|
||||
/// @return True only if ERC20 balances match and ERC721 token owners match.
|
||||
private static _compareExpectedAndRealBalances(
|
||||
expectedNewERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
realERC20BalancesByOwner: ERC20BalancesByOwner,
|
||||
expectedNewERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
realERC721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
) {
|
||||
// ERC20 Balances
|
||||
const erc20BalancesMatch = _.isEqual(expectedNewERC20BalancesByOwner, realERC20BalancesByOwner);
|
||||
if (!erc20BalancesMatch) {
|
||||
return false;
|
||||
}
|
||||
// ERC721 Token Ids
|
||||
const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues(
|
||||
expectedNewERC721TokenIdsByOwner,
|
||||
tokenIdsByOwner => {
|
||||
_.mapValues(tokenIdsByOwner, tokenIds => {
|
||||
_.sortBy(tokenIds);
|
||||
});
|
||||
},
|
||||
);
|
||||
const sortedNewERC721TokenIdsByOwner = _.mapValues(realERC721TokenIdsByOwner, tokenIdsByOwner => {
|
||||
_.mapValues(tokenIdsByOwner, tokenIds => {
|
||||
_.sortBy(tokenIds);
|
||||
});
|
||||
});
|
||||
const erc721TokenIdsMatch = _.isEqual(sortedExpectedNewERC721TokenIdsByOwner, sortedNewERC721TokenIdsByOwner);
|
||||
return erc721TokenIdsMatch;
|
||||
}
|
||||
|
||||
/// @dev Constructs new MatchOrderTester.
|
||||
/// @param exchangeWrapper Used to call to the Exchange.
|
||||
/// @param erc20Wrapper Used to fetch ERC20 balances.
|
||||
/// @param erc721Wrapper Used to fetch ERC721 token owners.
|
||||
constructor(exchangeWrapper: ExchangeWrapper, erc20Wrapper: ERC20Wrapper, erc721Wrapper: ERC721Wrapper) {
|
||||
this._exchangeWrapper = exchangeWrapper;
|
||||
this._erc20Wrapper = erc20Wrapper;
|
||||
this._erc721Wrapper = erc721Wrapper;
|
||||
}
|
||||
|
||||
/// @dev Matches two complementary orders and validates results.
|
||||
/// Validation either succeeds or throws.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param feeTokenAddress Address of ERC20 fee token.
|
||||
/// @param takerAddress Address of taker (the address who matched the two orders)
|
||||
/// @param erc20BalancesByOwner Current ERC20 balances.
|
||||
/// @param erc721TokenIdsByOwner Current ERC721 token owners.
|
||||
/// @param initialTakerAssetFilledAmountLeft Current amount the left order has been filled.
|
||||
/// @param initialTakerAssetFilledAmountRight Current amount the right order has been filled.
|
||||
/// @return New ERC20 balances & ERC721 token owners.
|
||||
public async matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
feeTokenAddress: string,
|
||||
takerAddress: string,
|
||||
erc20BalancesByOwner: ERC20BalancesByOwner,
|
||||
erc721TokenIdsByOwner: ERC721TokenIdsByOwner,
|
||||
initialTakerAssetFilledAmountLeft?: BigNumber,
|
||||
initialTakerAssetFilledAmountRight?: BigNumber,
|
||||
): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> {
|
||||
// Test setup & verify preconditions
|
||||
const makerAddressLeft = signedOrderLeft.makerAddress;
|
||||
const makerAddressRight = signedOrderRight.makerAddress;
|
||||
const feeRecipientAddressLeft = signedOrderLeft.feeRecipientAddress;
|
||||
const feeRecipientAddressRight = signedOrderRight.feeRecipientAddress;
|
||||
// Verify Left order preconditions
|
||||
const takerAssetFilledAmountBeforeLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderUtils.getOrderHashHex(signedOrderLeft),
|
||||
);
|
||||
const expectedLeftOrderFillAmoutBeforeMatch = initialTakerAssetFilledAmountLeft
|
||||
? initialTakerAssetFilledAmountLeft
|
||||
: new BigNumber(0);
|
||||
expect(takerAssetFilledAmountBeforeLeft).to.be.bignumber.equal(expectedLeftOrderFillAmoutBeforeMatch);
|
||||
// Verify Right order preconditions
|
||||
const takerAssetFilledAmountBeforeRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderUtils.getOrderHashHex(signedOrderRight),
|
||||
);
|
||||
const expectedRightOrderFillAmoutBeforeMatch = initialTakerAssetFilledAmountRight
|
||||
? initialTakerAssetFilledAmountRight
|
||||
: new BigNumber(0);
|
||||
expect(takerAssetFilledAmountBeforeRight).to.be.bignumber.equal(expectedRightOrderFillAmoutBeforeMatch);
|
||||
// Match left & right orders
|
||||
await this._exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress);
|
||||
const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync();
|
||||
const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync();
|
||||
// Calculate expected balance changes
|
||||
const expectedTransferAmounts = await this._calculateExpectedTransferAmountsAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
expectedLeftOrderFillAmoutBeforeMatch,
|
||||
expectedRightOrderFillAmoutBeforeMatch,
|
||||
);
|
||||
let expectedERC20BalancesByOwner: ERC20BalancesByOwner;
|
||||
let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner;
|
||||
[expectedERC20BalancesByOwner, expectedERC721TokenIdsByOwner] = MatchOrderTester._calculateExpectedBalances(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
feeTokenAddress,
|
||||
takerAddress,
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
expectedTransferAmounts,
|
||||
);
|
||||
// Assert our expected balances are equal to the actual balances
|
||||
const expectedBalancesMatchRealBalances = MatchOrderTester._compareExpectedAndRealBalances(
|
||||
expectedERC20BalancesByOwner,
|
||||
newERC20BalancesByOwner,
|
||||
expectedERC721TokenIdsByOwner,
|
||||
newERC721TokenIdsByOwner,
|
||||
);
|
||||
expect(expectedBalancesMatchRealBalances).to.be.true();
|
||||
return [newERC20BalancesByOwner, newERC721TokenIdsByOwner];
|
||||
}
|
||||
|
||||
/// @dev Calculates expected transfer amounts between order makers, fee recipients, and
|
||||
/// the taker when two orders are matched.
|
||||
/// @param signedOrderLeft First matched order.
|
||||
/// @param signedOrderRight Second matched order.
|
||||
/// @param expectedLeftOrderFillAmoutBeforeMatch How much we expect the left order has been filled, prior to matching orders.
|
||||
/// @param expectedRightOrderFillAmoutBeforeMatch How much we expect the right order has been filled, prior to matching orders.
|
||||
/// @return TransferAmounts A struct containing the expected transfer amounts.
|
||||
private async _calculateExpectedTransferAmountsAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
expectedLeftOrderFillAmoutBeforeMatch: BigNumber,
|
||||
expectedRightOrderFillAmoutBeforeMatch: BigNumber,
|
||||
): Promise<TransferAmounts> {
|
||||
let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderUtils.getOrderHashHex(signedOrderLeft),
|
||||
);
|
||||
amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(expectedLeftOrderFillAmoutBeforeMatch);
|
||||
const amountSoldByLeftMaker = amountBoughtByLeftMaker
|
||||
.times(signedOrderLeft.makerAssetAmount)
|
||||
.dividedToIntegerBy(signedOrderLeft.takerAssetAmount);
|
||||
const amountReceivedByRightMaker = amountBoughtByLeftMaker
|
||||
.times(signedOrderRight.takerAssetAmount)
|
||||
.dividedToIntegerBy(signedOrderRight.makerAssetAmount);
|
||||
const amountReceivedByTaker = amountSoldByLeftMaker.minus(amountReceivedByRightMaker);
|
||||
let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderUtils.getOrderHashHex(signedOrderRight),
|
||||
);
|
||||
amountBoughtByRightMaker = amountBoughtByRightMaker.minus(expectedRightOrderFillAmoutBeforeMatch);
|
||||
const amountSoldByRightMaker = amountBoughtByRightMaker
|
||||
.times(signedOrderRight.makerAssetAmount)
|
||||
.dividedToIntegerBy(signedOrderRight.takerAssetAmount);
|
||||
const amountReceivedByLeftMaker = amountSoldByRightMaker;
|
||||
const feePaidByLeftMaker = signedOrderLeft.makerFee
|
||||
.times(amountSoldByLeftMaker)
|
||||
.dividedToIntegerBy(signedOrderLeft.makerAssetAmount);
|
||||
const feePaidByRightMaker = signedOrderRight.makerFee
|
||||
.times(amountSoldByRightMaker)
|
||||
.dividedToIntegerBy(signedOrderRight.makerAssetAmount);
|
||||
const feePaidByTakerLeft = signedOrderLeft.takerFee
|
||||
.times(amountSoldByLeftMaker)
|
||||
.dividedToIntegerBy(signedOrderLeft.makerAssetAmount);
|
||||
const feePaidByTakerRight = signedOrderRight.takerFee
|
||||
.times(amountSoldByRightMaker)
|
||||
.dividedToIntegerBy(signedOrderRight.makerAssetAmount);
|
||||
const totalFeePaidByTaker = feePaidByTakerLeft.add(feePaidByTakerRight);
|
||||
const feeReceivedLeft = feePaidByLeftMaker.add(feePaidByTakerLeft);
|
||||
const feeReceivedRight = feePaidByRightMaker.add(feePaidByTakerRight);
|
||||
// Return values
|
||||
const expectedTransferAmounts = {
|
||||
// Left Maker
|
||||
amountBoughtByLeftMaker,
|
||||
amountSoldByLeftMaker,
|
||||
amountReceivedByLeftMaker,
|
||||
feePaidByLeftMaker,
|
||||
// Right Maker
|
||||
amountBoughtByRightMaker,
|
||||
amountSoldByRightMaker,
|
||||
amountReceivedByRightMaker,
|
||||
feePaidByRightMaker,
|
||||
// Taker
|
||||
amountReceivedByTaker,
|
||||
feePaidByTakerLeft,
|
||||
feePaidByTakerRight,
|
||||
totalFeePaidByTaker,
|
||||
// Fee Recipients
|
||||
feeReceivedLeft,
|
||||
feeReceivedRight,
|
||||
};
|
||||
return expectedTransferAmounts;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import chaiAsPromised = require('chai-as-promised');
|
||||
import ChaiBigNumber = require('chai-bignumber');
|
||||
@@ -9,5 +10,12 @@ export const chaiSetup = {
|
||||
chai.use(ChaiBigNumber());
|
||||
chai.use(dirtyChai);
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
// Node uses '.inspect()' instead of '.toString()' for log messages
|
||||
// HACK: Typescript won't allow me to mess with BigNumber.prototype
|
||||
// directly, so I create an instance and then get the prototype.
|
||||
Object.getPrototypeOf(new BigNumber(0)).inspect = function() {
|
||||
return this.toString();
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
24
yarn.lock
24
yarn.lock
@@ -1879,10 +1879,6 @@ buffer-from@^0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-0.1.2.tgz#15f4b9bcef012044df31142c14333caf6e0260d0"
|
||||
|
||||
buffer-from@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531"
|
||||
|
||||
buffer-indexof@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c"
|
||||
@@ -2513,7 +2509,15 @@ concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
|
||||
concat-stream@^1.4.10, concat-stream@^1.5.0, concat-stream@^1.5.1:
|
||||
concat-stream@^1.4.10, concat-stream@^1.5.0:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.1.tgz#261b8f518301f1d834e36342b9fea095d2620a26"
|
||||
dependencies:
|
||||
inherits "^2.0.3"
|
||||
readable-stream "^2.2.2"
|
||||
typedarray "^0.0.6"
|
||||
|
||||
concat-stream@^1.5.1:
|
||||
version "1.6.2"
|
||||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
|
||||
dependencies:
|
||||
@@ -10139,14 +10143,14 @@ semver-sort@0.0.4:
|
||||
semver "^5.0.3"
|
||||
semver-regex "^1.0.0"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@5.5.0, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
|
||||
semver@5.4.1, semver@~5.4.1:
|
||||
"semver@2 || 3 || 4 || 5", semver@5.4.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@~5.4.1:
|
||||
version "5.4.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
|
||||
|
||||
semver@5.5.0, semver@^5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||
|
||||
semver@^4.1.0:
|
||||
version "4.3.6"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da"
|
||||
|
||||
Reference in New Issue
Block a user