@0x/contracts-exchange-libs: Correct internal variable naming in src/index.ts.
`@0x/contracts-utils`: Correct internal variable naming in `src/index.ts`. `@0x/contracts-exchange`: Remove functions from `TestExchangeInternals.sol` that are now in other packages. `@0x/contracts-exchange`: Remove `TestExchangeMath.sol`. Exchange math functions are now tested in `@0x/contracts-exchange-libs`. `@0x/contracts-exchange`: Move `ReferenceFunctions` to default package export. `@0x/contracts-exchange`: Update `match_order.ts` tests to use reference math functions instead of `TestExchangeMath`. `@0x/contracts-exchange`: Remove `_updateFilledState()` combinatorial tests in favor of normal unit testing. Combinatorial testing was overkill. `@0x/contracts-exchange`: Update/refactor `calculateFillResults()` combinatorial tests to use the reference functions and hide them behind `TEST_ALL`.
This commit is contained in:
@@ -40,7 +40,6 @@
|
||||
"test/ReentrantERC20Token.sol",
|
||||
"test/TestAssetProxyDispatcher.sol",
|
||||
"test/TestExchangeInternals.sol",
|
||||
"test/TestExchangeMath.sol",
|
||||
"test/TestLibExchangeRichErrorDecoder.sol",
|
||||
"test/TestSignatureValidator.sol",
|
||||
"test/TestValidatorWallet.sol"
|
||||
|
||||
@@ -31,26 +31,6 @@ contract TestExchangeInternals is
|
||||
Exchange(chainId)
|
||||
{}
|
||||
|
||||
/// @dev Adds properties of both FillResults instances.
|
||||
/// Modifies the first FillResults instance specified.
|
||||
/// Note that this function has been modified from the original
|
||||
// internal version to return the FillResults.
|
||||
/// @param totalFillResults Fill results instance that will be added onto.
|
||||
/// @param singleFillResults Fill results instance that will be added to totalFillResults.
|
||||
/// @return newTotalFillResults The result of adding singleFillResults to totalFilResults.
|
||||
function addFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults)
|
||||
public
|
||||
pure
|
||||
returns (FillResults memory)
|
||||
{
|
||||
_addFillResults(totalFillResults, singleFillResults);
|
||||
return totalFillResults;
|
||||
}
|
||||
|
||||
/// @dev Calculates amounts filled and fees paid by maker and taker.
|
||||
/// @param order to be filled.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function calculateFillResults(
|
||||
Order memory order,
|
||||
uint256 takerAssetFilledAmount
|
||||
@@ -62,12 +42,9 @@ contract TestExchangeInternals is
|
||||
return _calculateFillResults(order, takerAssetFilledAmount);
|
||||
}
|
||||
|
||||
/// @dev Updates state with results of a fill order.
|
||||
/// @param order that was filled.
|
||||
/// @param takerAddress Address of taker who filled the order.
|
||||
/// @param orderTakerAssetFilledAmount Amount of order already filled.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function updateFilledState(
|
||||
/// @dev Call `_updateFilledState()` but first set `filled[order]` to
|
||||
/// `orderTakerAssetFilledAmount`.
|
||||
function testUpdateFilledState(
|
||||
Order memory order,
|
||||
address takerAddress,
|
||||
bytes32 orderHash,
|
||||
@@ -76,6 +53,7 @@ contract TestExchangeInternals is
|
||||
)
|
||||
public
|
||||
{
|
||||
filled[getOrderHash(order)] = orderTakerAssetFilledAmount;
|
||||
_updateFilledState(
|
||||
order,
|
||||
takerAddress,
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
|
||||
|
||||
contract TestExchangeMath is
|
||||
LibMath
|
||||
{
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// Reverts if rounding error is >= 0.1%
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function safeGetPartialAmountFloor(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
return _safeGetPartialAmountFloor(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// Reverts if rounding error is >= 0.1%
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function safeGetPartialAmountCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
return _safeGetPartialAmountCeil(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function getPartialAmountFloor(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
return _getPartialAmountFloor(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Calculates partial value given a numerator and denominator.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to calculate partial of.
|
||||
/// @return Partial value of target.
|
||||
function getPartialAmountCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256 partialAmount)
|
||||
{
|
||||
return _getPartialAmountCeil(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error >= 0.1%.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function isRoundingErrorFloor(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
return _isRoundingErrorFloor(numerator, denominator, target);
|
||||
}
|
||||
|
||||
/// @dev Checks if rounding error >= 0.1%.
|
||||
/// @param numerator Numerator.
|
||||
/// @param denominator Denominator.
|
||||
/// @param target Value to multiply with numerator/denominator.
|
||||
/// @return Rounding error is present.
|
||||
function isRoundingErrorCeil(
|
||||
uint256 numerator,
|
||||
uint256 denominator,
|
||||
uint256 target
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bool isError)
|
||||
{
|
||||
return _isRoundingErrorCeil(numerator, denominator, target);
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./generated-artifacts/@(Exchange|ExchangeWrapper|IAssetProxyDispatcher|IEIP1271Wallet|IExchange|IExchangeCore|IMatchOrders|ISignatureValidator|ITransactions|IWallet|IWrapperFunctions|IsolatedExchange|ReentrantERC20Token|TestAssetProxyDispatcher|TestExchangeInternals|TestExchangeMath|TestLibExchangeRichErrorDecoder|TestSignatureValidator|TestValidatorWallet|Whitelist).json",
|
||||
"abis": "./generated-artifacts/@(Exchange|ExchangeWrapper|IAssetProxyDispatcher|IEIP1271Wallet|IExchange|IExchangeCore|IMatchOrders|ISignatureValidator|ITransactions|IWallet|IWrapperFunctions|IsolatedExchange|ReentrantERC20Token|TestAssetProxyDispatcher|TestExchangeInternals|TestLibExchangeRichErrorDecoder|TestSignatureValidator|TestValidatorWallet|Whitelist).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@@ -20,7 +20,6 @@ import * as IsolatedExchange from '../generated-artifacts/IsolatedExchange.json'
|
||||
import * as ReentrantERC20Token from '../generated-artifacts/ReentrantERC20Token.json';
|
||||
import * as TestAssetProxyDispatcher from '../generated-artifacts/TestAssetProxyDispatcher.json';
|
||||
import * as TestExchangeInternals from '../generated-artifacts/TestExchangeInternals.json';
|
||||
import * as TestExchangeMath from '../generated-artifacts/TestExchangeMath.json';
|
||||
import * as TestLibExchangeRichErrorDecoder from '../generated-artifacts/TestLibExchangeRichErrorDecoder.json';
|
||||
import * as TestSignatureValidator from '../generated-artifacts/TestSignatureValidator.json';
|
||||
import * as TestValidatorWallet from '../generated-artifacts/TestValidatorWallet.json';
|
||||
@@ -38,11 +37,10 @@ export const artifacts = {
|
||||
ITransactions: ITransactions as ContractArtifact,
|
||||
IWallet: IWallet as ContractArtifact,
|
||||
IWrapperFunctions: IWrapperFunctions as ContractArtifact,
|
||||
IsolatedExchange: IsolatedExchange as ContractArtifact,
|
||||
ReentrantERC20Token: ReentrantERC20Token as ContractArtifact,
|
||||
TestAssetProxyDispatcher: TestAssetProxyDispatcher as ContractArtifact,
|
||||
TestExchangeInternals: TestExchangeInternals as ContractArtifact,
|
||||
TestExchangeMath: TestExchangeMath as ContractArtifact,
|
||||
IsolatedExchange: IsolatedExchange as ContractArtifact,
|
||||
TestLibExchangeRichErrorDecoder: TestLibExchangeRichErrorDecoder as ContractArtifact,
|
||||
TestSignatureValidator: TestSignatureValidator as ContractArtifact,
|
||||
TestValidatorWallet: TestValidatorWallet as ContractArtifact,
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
export * from './artifacts';
|
||||
export * from './wrappers';
|
||||
export * from '../test/utils';
|
||||
|
||||
import * as ReferenceFunctionsToExport from './reference_functions';
|
||||
export import ReferenceFunctions = ReferenceFunctionsToExport;
|
||||
|
||||
@@ -18,7 +18,6 @@ export * from '../generated-wrappers/isolated_exchange';
|
||||
export * from '../generated-wrappers/reentrant_erc20_token';
|
||||
export * from '../generated-wrappers/test_asset_proxy_dispatcher';
|
||||
export * from '../generated-wrappers/test_exchange_internals';
|
||||
export * from '../generated-wrappers/test_exchange_math';
|
||||
export * from '../generated-wrappers/test_lib_exchange_rich_error_decoder';
|
||||
export * from '../generated-wrappers/test_signature_validator';
|
||||
export * from '../generated-wrappers/test_validator_wallet';
|
||||
|
||||
@@ -1,426 +1,60 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
bytes32Values,
|
||||
constants,
|
||||
describe,
|
||||
expect,
|
||||
testCombinatoriallyWithReferenceFuncAsync,
|
||||
hexRandom,
|
||||
LogDecoder,
|
||||
testCombinatoriallyWithReferenceFunc,
|
||||
uint256Values,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { LibMathRevertErrors } from '@0x/order-utils';
|
||||
import { FillResults, Order, RevertReason, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, providerUtils, SafeMathRevertErrors } from '@0x/utils';
|
||||
import { FillResults, OrderWithoutDomain as Order } from '@0x/types';
|
||||
import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, TestExchangeInternalsContract, TestExchangeMathContract } from '../src';
|
||||
import {
|
||||
artifacts,
|
||||
ReferenceFunctions,
|
||||
TestExchangeInternalsContract,
|
||||
TestExchangeInternalsFillEventArgs,
|
||||
} from '../src';
|
||||
|
||||
const { MAX_UINT256 } = constants;
|
||||
|
||||
const emptyOrder: Order = {
|
||||
senderAddress: constants.NULL_ADDRESS,
|
||||
makerAddress: constants.NULL_ADDRESS,
|
||||
takerAddress: constants.NULL_ADDRESS,
|
||||
makerFee: new BigNumber(0),
|
||||
takerFee: new BigNumber(0),
|
||||
makerAssetAmount: new BigNumber(0),
|
||||
takerAssetAmount: new BigNumber(0),
|
||||
makerAssetData: '0x',
|
||||
takerAssetData: '0x',
|
||||
makerFeeAssetData: '0x',
|
||||
takerFeeAssetData: '0x',
|
||||
salt: new BigNumber(0),
|
||||
feeRecipientAddress: constants.NULL_ADDRESS,
|
||||
expirationTimeSeconds: new BigNumber(0),
|
||||
domain: {
|
||||
verifyingContractAddress: constants.NULL_ADDRESS,
|
||||
chainId: 0, // To be filled in later.
|
||||
},
|
||||
};
|
||||
|
||||
const emptySignedOrder: SignedOrder = {
|
||||
...emptyOrder,
|
||||
signature: '',
|
||||
};
|
||||
|
||||
const safeMathErrorForCall = new SafeMathRevertErrors.SafeMathError();
|
||||
|
||||
// TODO(dorothy-zbornak): Move this to `exchange-libs` and `utils`.
|
||||
blockchainTests.resets('Exchange math internal functions', env => {
|
||||
let chainId: number;
|
||||
let testExchange: TestExchangeMathContract;
|
||||
let divisionByZeroErrorForCall: Error | undefined;
|
||||
let roundingErrorForCall: Error | undefined;
|
||||
|
||||
before(async () => {
|
||||
chainId = await env.getChainIdAsync();
|
||||
emptyOrder.domain.chainId = chainId;
|
||||
emptySignedOrder.domain.chainId = chainId;
|
||||
|
||||
testExchange = await TestExchangeMathContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestExchangeMath,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
);
|
||||
divisionByZeroErrorForCall = new Error(RevertReason.DivisionByZero);
|
||||
roundingErrorForCall = new Error(RevertReason.RoundingError);
|
||||
divisionByZeroErrorForCall = new LibMathRevertErrors.DivisionByZeroError();
|
||||
roundingErrorForCall = new LibMathRevertErrors.RoundingError();
|
||||
});
|
||||
|
||||
async function referenceIsRoundingErrorFloorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<boolean> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
if (numerator.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
if (target.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
const product = numerator.multipliedBy(target);
|
||||
const remainder = product.mod(denominator);
|
||||
const remainderTimes1000 = remainder.multipliedBy('1000');
|
||||
const isError = remainderTimes1000.gte(product);
|
||||
if (product.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
if (remainderTimes1000.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
return isError;
|
||||
}
|
||||
|
||||
async function referenceIsRoundingErrorCeilAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<boolean> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
if (numerator.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
if (target.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
const product = numerator.multipliedBy(target);
|
||||
const remainder = product.mod(denominator);
|
||||
const error = denominator.minus(remainder).mod(denominator);
|
||||
const errorTimes1000 = error.multipliedBy('1000');
|
||||
const isError = errorTimes1000.gte(product);
|
||||
if (product.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
if (errorTimes1000.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
return isError;
|
||||
}
|
||||
|
||||
async function referenceSafeGetPartialAmountFloorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
const isRoundingError = await referenceIsRoundingErrorFloorAsync(numerator, denominator, target);
|
||||
if (isRoundingError) {
|
||||
throw roundingErrorForCall;
|
||||
}
|
||||
const product = numerator.multipliedBy(target);
|
||||
if (product.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
return product.dividedToIntegerBy(denominator);
|
||||
}
|
||||
|
||||
describe('getPartialAmountFloor', async () => {
|
||||
async function referenceGetPartialAmountFloorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
const product = numerator.multipliedBy(target);
|
||||
if (product.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
return product.dividedToIntegerBy(denominator);
|
||||
}
|
||||
async function testGetPartialAmountFloorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
return testExchange.getPartialAmountFloor.callAsync(numerator, denominator, target);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'getPartialAmountFloor',
|
||||
referenceGetPartialAmountFloorAsync,
|
||||
testGetPartialAmountFloorAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
|
||||
describe('getPartialAmountCeil', async () => {
|
||||
async function referenceGetPartialAmountCeilAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
const product = numerator.multipliedBy(target);
|
||||
const offset = product.plus(denominator.minus(1));
|
||||
if (offset.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
const result = offset.dividedToIntegerBy(denominator);
|
||||
if (product.mod(denominator).eq(0)) {
|
||||
expect(result.multipliedBy(denominator)).to.be.bignumber.eq(product);
|
||||
} else {
|
||||
expect(result.multipliedBy(denominator)).to.be.bignumber.gt(product);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
async function testGetPartialAmountCeilAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
return testExchange.getPartialAmountCeil.callAsync(numerator, denominator, target);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'getPartialAmountCeil',
|
||||
referenceGetPartialAmountCeilAsync,
|
||||
testGetPartialAmountCeilAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
|
||||
describe('safeGetPartialAmountFloor', async () => {
|
||||
async function testSafeGetPartialAmountFloorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
return testExchange.safeGetPartialAmountFloor.callAsync(numerator, denominator, target);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'safeGetPartialAmountFloor',
|
||||
referenceSafeGetPartialAmountFloorAsync,
|
||||
testSafeGetPartialAmountFloorAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
|
||||
describe('safeGetPartialAmountCeil', async () => {
|
||||
async function referenceSafeGetPartialAmountCeilAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
const isRoundingError = await referenceIsRoundingErrorCeilAsync(numerator, denominator, target);
|
||||
if (isRoundingError) {
|
||||
throw roundingErrorForCall;
|
||||
}
|
||||
const product = numerator.multipliedBy(target);
|
||||
const offset = product.plus(denominator.minus(1));
|
||||
if (offset.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
const result = offset.dividedToIntegerBy(denominator);
|
||||
if (product.mod(denominator).eq(0)) {
|
||||
expect(result.multipliedBy(denominator)).to.be.bignumber.eq(product);
|
||||
} else {
|
||||
expect(result.multipliedBy(denominator)).to.be.bignumber.gt(product);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
async function testSafeGetPartialAmountCeilAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
return testExchange.safeGetPartialAmountCeil.callAsync(numerator, denominator, target);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'safeGetPartialAmountCeil',
|
||||
referenceSafeGetPartialAmountCeilAsync,
|
||||
testSafeGetPartialAmountCeilAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
|
||||
describe('isRoundingErrorFloor', async () => {
|
||||
async function testIsRoundingErrorFloorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<boolean> {
|
||||
return testExchange.isRoundingErrorFloor.callAsync(numerator, denominator, target);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'isRoundingErrorFloor',
|
||||
referenceIsRoundingErrorFloorAsync,
|
||||
testIsRoundingErrorFloorAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
|
||||
describe('isRoundingErrorCeil', async () => {
|
||||
async function testIsRoundingErrorCeilAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<boolean> {
|
||||
return testExchange.isRoundingErrorCeil.callAsync(numerator, denominator, target);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'isRoundingErrorCeil',
|
||||
referenceIsRoundingErrorCeilAsync,
|
||||
testIsRoundingErrorCeilAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO(dorothy-zbornak): Add _settleOrder, _dispatchTransferFrom
|
||||
blockchainTests.resets('Exchange core internal functions', env => {
|
||||
let chainId: number;
|
||||
// TODO(dorothy-zbornak): Add _settleOrder
|
||||
blockchainTests.only('Exchange core internal functions', env => {
|
||||
const CHAIN_ID = 1337;
|
||||
const EMPTY_ORDER: Order = {
|
||||
senderAddress: constants.NULL_ADDRESS,
|
||||
makerAddress: constants.NULL_ADDRESS,
|
||||
takerAddress: constants.NULL_ADDRESS,
|
||||
makerFee: constants.ZERO_AMOUNT,
|
||||
takerFee: constants.ZERO_AMOUNT,
|
||||
makerAssetAmount: constants.ZERO_AMOUNT,
|
||||
takerAssetAmount: constants.ZERO_AMOUNT,
|
||||
makerAssetData: constants.NULL_BYTES,
|
||||
takerAssetData: constants.NULL_BYTES,
|
||||
makerFeeAssetData: constants.NULL_BYTES,
|
||||
takerFeeAssetData: constants.NULL_BYTES,
|
||||
salt: constants.ZERO_AMOUNT,
|
||||
feeRecipientAddress: constants.NULL_ADDRESS,
|
||||
expirationTimeSeconds: constants.ZERO_AMOUNT,
|
||||
};
|
||||
let testExchange: TestExchangeInternalsContract;
|
||||
let safeMathErrorForSendTransaction: Error | undefined;
|
||||
let divisionByZeroErrorForCall: Error | undefined;
|
||||
let roundingErrorForCall: Error | undefined;
|
||||
let logDecoder: LogDecoder;
|
||||
let senderAddress: string;
|
||||
|
||||
before(async () => {
|
||||
chainId = await providerUtils.getChainIdAsync(env.provider);
|
||||
emptyOrder.domain.chainId = chainId;
|
||||
emptySignedOrder.domain.chainId = chainId;
|
||||
|
||||
[ senderAddress ] = await env.getAccountAddressesAsync();
|
||||
testExchange = await TestExchangeInternalsContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestExchangeInternals,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
divisionByZeroErrorForCall = new Error(RevertReason.DivisionByZero);
|
||||
roundingErrorForCall = new Error(RevertReason.RoundingError);
|
||||
safeMathErrorForSendTransaction = safeMathErrorForCall;
|
||||
divisionByZeroErrorForCall = new LibMathRevertErrors.DivisionByZeroError();
|
||||
roundingErrorForCall = new LibMathRevertErrors.RoundingError();
|
||||
});
|
||||
// Note(albrow): Don't forget to add beforeEach and afterEach calls to reset
|
||||
// the blockchain state for any tests which modify it!
|
||||
|
||||
async function referenceIsRoundingErrorFloorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<boolean> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
if (numerator.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
if (target.eq(0)) {
|
||||
return false;
|
||||
}
|
||||
const product = numerator.multipliedBy(target);
|
||||
const remainder = product.mod(denominator);
|
||||
const remainderTimes1000 = remainder.multipliedBy('1000');
|
||||
const isError = remainderTimes1000.gte(product);
|
||||
if (product.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
if (remainderTimes1000.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
return isError;
|
||||
}
|
||||
|
||||
async function referenceSafeGetPartialAmountFloorAsync(
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
target: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
if (denominator.eq(0)) {
|
||||
throw divisionByZeroErrorForCall;
|
||||
}
|
||||
const isRoundingError = await referenceIsRoundingErrorFloorAsync(numerator, denominator, target);
|
||||
if (isRoundingError) {
|
||||
throw roundingErrorForCall;
|
||||
}
|
||||
const product = numerator.multipliedBy(target);
|
||||
if (product.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
return product.dividedToIntegerBy(denominator);
|
||||
}
|
||||
|
||||
// TODO(dorothy-zbornak): Move this to `exchange-libs`.
|
||||
describe('addFillResults', async () => {
|
||||
function makeFillResults(value: BigNumber): FillResults {
|
||||
return {
|
||||
makerAssetFilledAmount: value,
|
||||
takerAssetFilledAmount: value,
|
||||
makerFeePaid: value,
|
||||
takerFeePaid: value,
|
||||
};
|
||||
}
|
||||
async function referenceAddFillResultsAsync(
|
||||
totalValue: BigNumber,
|
||||
singleValue: BigNumber,
|
||||
): Promise<FillResults> {
|
||||
// Note(albrow): Here, each of totalFillResults and
|
||||
// singleFillResults will consist of fields with the same values.
|
||||
// This should be safe because none of the fields in a given
|
||||
// FillResults are ever used together in a mathemetical operation.
|
||||
// They are only used with the corresponding field from *the other*
|
||||
// FillResults, which are different.
|
||||
const totalFillResults = makeFillResults(totalValue);
|
||||
const singleFillResults = makeFillResults(singleValue);
|
||||
// HACK(albrow): _.mergeWith mutates the first argument! To
|
||||
// workaround this we use _.cloneDeep.
|
||||
return _.mergeWith(
|
||||
_.cloneDeep(totalFillResults),
|
||||
singleFillResults,
|
||||
(totalVal: BigNumber, singleVal: BigNumber) => {
|
||||
const newTotal = totalVal.plus(singleVal);
|
||||
if (newTotal.isGreaterThan(MAX_UINT256)) {
|
||||
throw safeMathErrorForCall;
|
||||
}
|
||||
return newTotal;
|
||||
},
|
||||
);
|
||||
}
|
||||
async function testAddFillResultsAsync(totalValue: BigNumber, singleValue: BigNumber): Promise<FillResults> {
|
||||
const totalFillResults = makeFillResults(totalValue);
|
||||
const singleFillResults = makeFillResults(singleValue);
|
||||
return testExchange.addFillResults.callAsync(totalFillResults, singleFillResults);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'addFillResults',
|
||||
referenceAddFillResultsAsync,
|
||||
testAddFillResultsAsync,
|
||||
[uint256Values, uint256Values],
|
||||
new BigNumber(CHAIN_ID),
|
||||
);
|
||||
logDecoder = new LogDecoder(env.web3Wrapper, artifacts);
|
||||
});
|
||||
|
||||
describe('calculateFillResults', async () => {
|
||||
blockchainTests('calculateFillResults', async () => {
|
||||
function makeOrder(
|
||||
makerAssetAmount: BigNumber,
|
||||
takerAssetAmount: BigNumber,
|
||||
@@ -428,13 +62,14 @@ blockchainTests.resets('Exchange core internal functions', env => {
|
||||
takerFee: BigNumber,
|
||||
): Order {
|
||||
return {
|
||||
...emptyOrder,
|
||||
...EMPTY_ORDER,
|
||||
makerAssetAmount,
|
||||
takerAssetAmount,
|
||||
makerFee,
|
||||
takerFee,
|
||||
};
|
||||
}
|
||||
|
||||
async function referenceCalculateFillResultsAsync(
|
||||
orderTakerAssetAmount: BigNumber,
|
||||
takerAssetFilledAmount: BigNumber,
|
||||
@@ -446,28 +81,12 @@ blockchainTests.resets('Exchange core internal functions', env => {
|
||||
// in any mathematical operation in either the reference TypeScript
|
||||
// implementation or the Solidity implementation of
|
||||
// calculateFillResults.
|
||||
const makerAssetFilledAmount = await referenceSafeGetPartialAmountFloorAsync(
|
||||
return ReferenceFunctions.calculateFillResults(
|
||||
makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount),
|
||||
takerAssetFilledAmount,
|
||||
orderTakerAssetAmount,
|
||||
otherAmount,
|
||||
);
|
||||
const order = makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount);
|
||||
const orderMakerAssetAmount = order.makerAssetAmount;
|
||||
return {
|
||||
makerAssetFilledAmount,
|
||||
takerAssetFilledAmount,
|
||||
makerFeePaid: await referenceSafeGetPartialAmountFloorAsync(
|
||||
makerAssetFilledAmount,
|
||||
orderMakerAssetAmount,
|
||||
otherAmount,
|
||||
),
|
||||
takerFeePaid: await referenceSafeGetPartialAmountFloorAsync(
|
||||
takerAssetFilledAmount,
|
||||
orderTakerAssetAmount,
|
||||
otherAmount,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
async function testCalculateFillResultsAsync(
|
||||
orderTakerAssetAmount: BigNumber,
|
||||
takerAssetFilledAmount: BigNumber,
|
||||
@@ -476,57 +95,126 @@ blockchainTests.resets('Exchange core internal functions', env => {
|
||||
const order = makeOrder(otherAmount, orderTakerAssetAmount, otherAmount, otherAmount);
|
||||
return testExchange.calculateFillResults.callAsync(order, takerAssetFilledAmount);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'calculateFillResults',
|
||||
referenceCalculateFillResultsAsync,
|
||||
testCalculateFillResultsAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
|
||||
describe.optional('combinatorial tests', () => {
|
||||
testCombinatoriallyWithReferenceFunc(
|
||||
'calculateFillResults',
|
||||
referenceCalculateFillResultsAsync,
|
||||
testCalculateFillResultsAsync,
|
||||
[uint256Values, uint256Values, uint256Values],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
blockchainTests.resets('updateFilledState', async ({ web3Wrapper }) => {
|
||||
async function referenceUpdateFilledStateAsync(
|
||||
takerAssetFilledAmount: BigNumber,
|
||||
orderTakerAssetFilledAmount: BigNumber,
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
orderHash: string,
|
||||
): Promise<BigNumber> {
|
||||
const totalFilledAmount = takerAssetFilledAmount.plus(orderTakerAssetFilledAmount);
|
||||
if (totalFilledAmount.isGreaterThan(MAX_UINT256)) {
|
||||
// FIXME throw safeMathErrorForSendTransaction(takerAssetFilledAmount, orderTakerAssetFilledAmount);
|
||||
throw safeMathErrorForSendTransaction;
|
||||
}
|
||||
return totalFilledAmount;
|
||||
blockchainTests.resets('updateFilledState', async () => {
|
||||
const ONE_ETHER = new BigNumber(1e18);
|
||||
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
|
||||
const randomHash = () => hexRandom(constants.WORD_LENGTH);
|
||||
const randomAssetData = () => hexRandom(36);
|
||||
const ORDER_DEFAULTS = {
|
||||
senderAddress: randomAddress(),
|
||||
makerAddress: randomAddress(),
|
||||
takerAddress: randomAddress(),
|
||||
makerFee: ONE_ETHER.times(0.001),
|
||||
takerFee: ONE_ETHER.times(0.003),
|
||||
makerAssetAmount: ONE_ETHER,
|
||||
takerAssetAmount: ONE_ETHER.times(0.5),
|
||||
makerAssetData: randomAssetData(),
|
||||
takerAssetData: randomAssetData(),
|
||||
makerFeeAssetData: randomAssetData(),
|
||||
takerFeeAssetData: randomAssetData(),
|
||||
salt: new BigNumber(_.random(0, 1e8)),
|
||||
feeRecipientAddress: randomAddress(),
|
||||
expirationTimeSeconds: new BigNumber(_.random(0, 1e8)),
|
||||
};
|
||||
|
||||
function makeOrder(details?: Partial<Order>): Order {
|
||||
return _.assign(
|
||||
{},
|
||||
ORDER_DEFAULTS,
|
||||
details,
|
||||
);
|
||||
}
|
||||
|
||||
async function testUpdateFilledStateAsync(
|
||||
takerAssetFilledAmount: BigNumber,
|
||||
order: Order,
|
||||
orderTakerAssetFilledAmount: BigNumber,
|
||||
orderHash: string,
|
||||
): Promise<BigNumber> {
|
||||
const fillResults = {
|
||||
makerAssetFilledAmount: new BigNumber(0),
|
||||
takerAssetFilledAmount,
|
||||
makerFeePaid: new BigNumber(0),
|
||||
takerFeePaid: new BigNumber(0),
|
||||
};
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await testExchange.updateFilledState.sendTransactionAsync(
|
||||
emptySignedOrder,
|
||||
constants.NULL_ADDRESS,
|
||||
takerAddress: string,
|
||||
takerAssetFillAmount: BigNumber,
|
||||
): Promise<void> {
|
||||
const orderHash = randomHash();
|
||||
const fillResults = ReferenceFunctions.calculateFillResults(
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
);
|
||||
const expectedFilledState = orderTakerAssetFilledAmount.plus(takerAssetFillAmount);
|
||||
// CAll `testUpdateFilledState()`, which will set the `filled`
|
||||
// state for this order to `orderTakerAssetFilledAmount` before
|
||||
// calling `_updateFilledState()`.
|
||||
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||
await testExchange.testUpdateFilledState.sendTransactionAsync(
|
||||
order,
|
||||
takerAddress,
|
||||
orderHash,
|
||||
orderTakerAssetFilledAmount,
|
||||
fillResults,
|
||||
),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
return testExchange.filled.callAsync(orderHash);
|
||||
// Grab the new `filled` state for this order.
|
||||
const actualFilledState = await testExchange.filled.callAsync(orderHash);
|
||||
// Assert the `filled` state for this order.
|
||||
expect(actualFilledState).to.bignumber.eq(expectedFilledState);
|
||||
// Assert the logs.
|
||||
const fillEvent = receipt.logs[0] as LogWithDecodedArgs<TestExchangeInternalsFillEventArgs>;
|
||||
expect(fillEvent.event).to.eq('Fill');
|
||||
expect(fillEvent.args.makerAddress).to.eq(order.makerAddress);
|
||||
expect(fillEvent.args.feeRecipientAddress).to.eq(order.feeRecipientAddress);
|
||||
expect(fillEvent.args.makerAssetData).to.eq(order.makerAssetData);
|
||||
expect(fillEvent.args.takerAssetData).to.eq(order.takerAssetData);
|
||||
expect(fillEvent.args.makerFeeAssetData).to.eq(order.makerFeeAssetData);
|
||||
expect(fillEvent.args.takerFeeAssetData).to.eq(order.takerFeeAssetData);
|
||||
expect(fillEvent.args.makerAssetFilledAmount).to.bignumber.eq(fillResults.makerAssetFilledAmount);
|
||||
expect(fillEvent.args.takerAssetFilledAmount).to.bignumber.eq(fillResults.takerAssetFilledAmount);
|
||||
expect(fillEvent.args.makerFeePaid).to.bignumber.eq(fillResults.makerFeePaid);
|
||||
expect(fillEvent.args.takerFeePaid).to.bignumber.eq(fillResults.takerFeePaid);
|
||||
expect(fillEvent.args.takerAddress).to.eq(takerAddress);
|
||||
expect(fillEvent.args.senderAddress).to.eq(senderAddress);
|
||||
expect(fillEvent.args.orderHash).to.eq(orderHash);
|
||||
}
|
||||
await testCombinatoriallyWithReferenceFuncAsync(
|
||||
'updateFilledState',
|
||||
referenceUpdateFilledStateAsync,
|
||||
testUpdateFilledStateAsync,
|
||||
[uint256Values, uint256Values, bytes32Values],
|
||||
);
|
||||
|
||||
it('emits a `Fill` event and updates `filled` state correctly', async () => {
|
||||
const order = makeOrder();
|
||||
return testUpdateFilledStateAsync(
|
||||
order,
|
||||
order.takerAssetAmount.times(0.1),
|
||||
randomAddress(),
|
||||
order.takerAssetAmount.times(0.25),
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if `leftOrderTakerAssetFilledAmount + fillResults.takerAssetFilledAmount` overflows', async () => {
|
||||
const order = makeOrder();
|
||||
const orderTakerAssetFilledAmount = constants.MAX_UINT256.dividedToIntegerBy(2);
|
||||
const takerAssetFillAmount = constants.MAX_UINT256.dividedToIntegerBy(2).plus(2);
|
||||
const fillResults = {
|
||||
makerAssetFilledAmount: constants.ZERO_AMOUNT,
|
||||
takerAssetFilledAmount: takerAssetFillAmount,
|
||||
makerFeePaid: constants.ZERO_AMOUNT,
|
||||
takerFeePaid: constants.ZERO_AMOUNT,
|
||||
};
|
||||
const expectedError = new SafeMathRevertErrors.SafeMathError(
|
||||
SafeMathRevertErrors.SafeMathErrorCodes.Uint256AdditionOverflow,
|
||||
orderTakerAssetFilledAmount,
|
||||
takerAssetFillAmount,
|
||||
);
|
||||
return expect(testExchange.testUpdateFilledState.awaitTransactionSuccessAsync(
|
||||
order,
|
||||
randomAddress(),
|
||||
randomHash(),
|
||||
orderTakerAssetFilledAmount,
|
||||
fillResults,
|
||||
)).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:disable-line:max-file-line-count
|
||||
|
||||
@@ -9,6 +9,8 @@ import { FillResults, OrderInfo, OrderStatus, SignatureType } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { calculateFillResults } from '../src/reference_functions';
|
||||
|
||||
import {
|
||||
AssetBalances,
|
||||
createBadAssetData,
|
||||
@@ -18,9 +20,8 @@ import {
|
||||
IsolatedExchangeWrapper,
|
||||
Order,
|
||||
} from './utils/isolated_exchange_wrapper';
|
||||
import { calculateFillResults } from './utils/reference_functions';
|
||||
|
||||
blockchainTests.only('Isolated fillOrder() tests', env => {
|
||||
blockchainTests('Isolated fillOrder() tests', env => {
|
||||
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
|
||||
const getCurrentTime = () => Math.floor(_.now() / 1000);
|
||||
const { ZERO_AMOUNT } = constants;
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
import { ERC1155Contract as ERC1155TokenContract, Erc1155Wrapper as ERC1155Wrapper } from '@0x/contracts-erc1155';
|
||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||
import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs';
|
||||
import {
|
||||
chaiSetup,
|
||||
constants,
|
||||
@@ -34,7 +35,6 @@ import {
|
||||
ExchangeContract,
|
||||
ExchangeWrapper,
|
||||
ReentrantERC20TokenContract,
|
||||
TestExchangeMathContract,
|
||||
} from '../src';
|
||||
|
||||
import { MatchOrderTester, TokenBalances } from './utils/match_order_tester';
|
||||
@@ -42,6 +42,7 @@ import { MatchOrderTester, TokenBalances } from './utils/match_order_tester';
|
||||
const ZERO = new BigNumber(0);
|
||||
const ONE = new BigNumber(1);
|
||||
const TWO = new BigNumber(2);
|
||||
const { isRoundingErrorCeil, isRoundingErrorFloor } = LibReferenceFunctions;
|
||||
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
chaiSetup.configure();
|
||||
@@ -88,8 +89,6 @@ describe('matchOrders', () => {
|
||||
|
||||
let matchOrderTester: MatchOrderTester;
|
||||
|
||||
let testExchangeMath: TestExchangeMathContract;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
@@ -240,11 +239,6 @@ describe('matchOrders', () => {
|
||||
orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft);
|
||||
const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
|
||||
orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight);
|
||||
testExchangeMath = await TestExchangeMathContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestExchangeMath,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
// Create match order tester
|
||||
matchOrderTester = new MatchOrderTester(exchangeWrapper, erc20Wrapper, erc721Wrapper, erc1155ProxyWrapper);
|
||||
tokenBalances = await matchOrderTester.getBalancesAsync();
|
||||
@@ -276,18 +270,18 @@ describe('matchOrders', () => {
|
||||
const numerator = signedOrderLeft.makerAssetAmount;
|
||||
const denominator = signedOrderLeft.takerAssetAmount;
|
||||
const target = signedOrderRight.makerAssetAmount;
|
||||
const isRoundingErrorCeil = await testExchangeMath.isRoundingErrorCeil.callAsync(
|
||||
const _isRoundingErrorCeil = isRoundingErrorCeil(
|
||||
numerator,
|
||||
denominator,
|
||||
target,
|
||||
);
|
||||
expect(isRoundingErrorCeil).to.be.true();
|
||||
const isRoundingErrorFloor = await testExchangeMath.isRoundingErrorFloor.callAsync(
|
||||
expect(_isRoundingErrorCeil).to.be.true();
|
||||
const _isRoundingErrorFloor = isRoundingErrorFloor(
|
||||
numerator,
|
||||
denominator,
|
||||
target,
|
||||
);
|
||||
expect(isRoundingErrorFloor).to.be.false();
|
||||
expect(_isRoundingErrorFloor).to.be.false();
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
// Note that the left maker received a slightly better sell price.
|
||||
// This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
|
||||
@@ -342,20 +336,19 @@ describe('matchOrders', () => {
|
||||
const numerator = signedOrderRight.takerAssetAmount;
|
||||
const denominator = signedOrderRight.makerAssetAmount;
|
||||
const target = signedOrderLeft.takerAssetAmount;
|
||||
const isRoundingErrorFloor = await testExchangeMath.isRoundingErrorFloor.callAsync(
|
||||
const _isRoundingErrorFloor = isRoundingErrorFloor(
|
||||
numerator,
|
||||
denominator,
|
||||
target,
|
||||
);
|
||||
expect(isRoundingErrorFloor).to.be.true();
|
||||
const isRoundingErrorCeil = await testExchangeMath.isRoundingErrorCeil.callAsync(
|
||||
expect(_isRoundingErrorFloor).to.be.true();
|
||||
const _isRoundingErrorCeil = isRoundingErrorCeil(
|
||||
numerator,
|
||||
denominator,
|
||||
target,
|
||||
);
|
||||
expect(isRoundingErrorCeil).to.be.false();
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
// Note that the right maker received a slightly better purchase price.
|
||||
expect(_isRoundingErrorCeil).to.be.false();
|
||||
// Match signedOrderLeft isRoundingErrorFloor right maker received a slightly better purchase price.
|
||||
// This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
|
||||
// Because the right maker received a slightly more favorable buy price, the fee
|
||||
// paid by the right taker is slightly higher than that paid by the right maker.
|
||||
@@ -1421,18 +1414,18 @@ describe('matchOrders', () => {
|
||||
const numerator = signedOrderLeft.makerAssetAmount;
|
||||
const denominator = signedOrderLeft.takerAssetAmount;
|
||||
const target = signedOrderRight.makerAssetAmount;
|
||||
const isRoundingErrorCeil = await testExchangeMath.isRoundingErrorCeil.callAsync(
|
||||
const _isRoundingErrorCeil = isRoundingErrorCeil(
|
||||
numerator,
|
||||
denominator,
|
||||
target,
|
||||
);
|
||||
expect(isRoundingErrorCeil).to.be.true();
|
||||
const isRoundingErrorFloor = await testExchangeMath.isRoundingErrorFloor.callAsync(
|
||||
expect(_isRoundingErrorCeil).to.be.true();
|
||||
const _isRoundingErrorFloor = isRoundingErrorFloor(
|
||||
numerator,
|
||||
denominator,
|
||||
target,
|
||||
);
|
||||
expect(isRoundingErrorFloor).to.be.false();
|
||||
expect(_isRoundingErrorFloor).to.be.false();
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
// Note that the left maker received a slightly better sell price.
|
||||
// This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
|
||||
@@ -1487,18 +1480,18 @@ describe('matchOrders', () => {
|
||||
const numerator = signedOrderRight.makerAssetAmount;
|
||||
const denominator = signedOrderRight.takerAssetAmount;
|
||||
const target = signedOrderLeft.makerAssetAmount;
|
||||
const isRoundingErrorCeil = await testExchangeMath.isRoundingErrorCeil.callAsync(
|
||||
const _isRoundingErrorCeil = isRoundingErrorCeil(
|
||||
numerator,
|
||||
denominator,
|
||||
target,
|
||||
);
|
||||
expect(isRoundingErrorCeil).to.be.false();
|
||||
const isRoundingErrorFloor = await testExchangeMath.isRoundingErrorFloor.callAsync(
|
||||
expect(_isRoundingErrorCeil).to.be.false();
|
||||
const _isRoundingErrorFloor = isRoundingErrorFloor(
|
||||
numerator,
|
||||
denominator,
|
||||
target,
|
||||
);
|
||||
expect(isRoundingErrorFloor).to.be.false();
|
||||
expect(_isRoundingErrorFloor).to.be.false();
|
||||
// Match signedOrderLeft with signedOrderRight
|
||||
// Note that the right maker received a slightly better purchase price.
|
||||
// This is intentional; see note in MixinMatchOrders.calculateMatchedFillResults.
|
||||
|
||||
@@ -156,7 +156,7 @@ export function createBadSignature(type: SignatureType = SignatureType.EIP712):
|
||||
return `0x00${Buffer.from([type]).toString('hex')}`;
|
||||
}
|
||||
|
||||
const ERC20_ASSET_DATA_LENGTH = 24;
|
||||
const ERC20_ASSET_DATA_LENGTH = 36;
|
||||
|
||||
/**
|
||||
* Create asset data for the `IsolatedExchange` contract that will pass.
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
"generated-artifacts/ReentrantERC20Token.json",
|
||||
"generated-artifacts/TestAssetProxyDispatcher.json",
|
||||
"generated-artifacts/TestExchangeInternals.json",
|
||||
"generated-artifacts/TestExchangeMath.json",
|
||||
"generated-artifacts/TestLibExchangeRichErrorDecoder.json",
|
||||
"generated-artifacts/TestSignatureValidator.json",
|
||||
"generated-artifacts/TestValidatorWallet.json",
|
||||
|
||||
Reference in New Issue
Block a user