feat: Enable partial Native order fills. Union intermediary tokens (#309)

* feat: Enable partial Native order fills

* change intermediary tokens to be a UNION.

Hint to cvxCRV and CRV

* Pin asset-swapper to use contracts-zero-ex 0.27.0 for now

* feat: Retire Eth2Dai/Oasis
This commit is contained in:
Jacob Evans 2021-08-19 15:21:23 +10:00 committed by GitHub
parent 68656b4a4d
commit 9727f0cebe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 105 additions and 778 deletions

View File

@ -1,4 +1,21 @@
[
{
"version": "16.26.0",
"changes": [
{
"note": "feat: Enable partial Native fills to be consumed, previously for v3 they were dropped",
"pr": 309
},
{
"note": "feat: Modify Intermediate tokens to be a union",
"pr": 309
},
{
"note": "feat: Retire Eth2Dai/Oasis",
"pr": 309
}
]
},
{
"version": "16.25.0",
"changes": [

View File

@ -26,7 +26,6 @@ import "./BancorSampler.sol";
import "./CurveSampler.sol";
import "./DODOSampler.sol";
import "./DODOV2Sampler.sol";
import "./Eth2DaiSampler.sol";
import "./KyberSampler.sol";
import "./KyberDmmSampler.sol";
import "./LidoSampler.sol";
@ -52,7 +51,6 @@ contract ERC20BridgeSampler is
CurveSampler,
DODOSampler,
DODOV2Sampler,
Eth2DaiSampler,
KyberSampler,
KyberDmmSampler,
LidoSampler,

View File

@ -1,110 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 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.6;
pragma experimental ABIEncoderV2;
import "./interfaces/IEth2Dai.sol";
import "./SamplerUtils.sol";
contract Eth2DaiSampler is
SamplerUtils
{
/// @dev Base gas limit for Eth2Dai calls.
uint256 constant private ETH2DAI_CALL_GAS = 1000e3; // 1m
/// @dev Sample sell quotes from Eth2Dai/Oasis.
/// @param router Address of the Eth2Dai/Oasis contract
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
/// @param takerTokenAmounts Taker token sell amount for each sample.
/// @return makerTokenAmounts Maker amounts bought at each taker token
/// amount.
function sampleSellsFromEth2Dai(
address router,
address takerToken,
address makerToken,
uint256[] memory takerTokenAmounts
)
public
view
returns (uint256[] memory makerTokenAmounts)
{
_assertValidPair(makerToken, takerToken);
uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples);
for (uint256 i = 0; i < numSamples; i++) {
try
IEth2Dai(router).getBuyAmount
{gas: ETH2DAI_CALL_GAS}
(makerToken, takerToken, takerTokenAmounts[i])
returns (uint256 amount)
{
makerTokenAmounts[i] = amount;
// Break early if there are 0 amounts
if (makerTokenAmounts[i] == 0) {
break;
}
} catch (bytes memory) {
// Swallow failures, leaving all results as zero.
break;
}
}
}
/// @dev Sample buy quotes from Eth2Dai/Oasis.
/// @param router Address of the Eth2Dai/Oasis contract
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
/// @param takerTokenAmounts Maker token sell amount for each sample.
/// @return takerTokenAmounts Taker amounts sold at each maker token
/// amount.
function sampleBuysFromEth2Dai(
address router,
address takerToken,
address makerToken,
uint256[] memory makerTokenAmounts
)
public
view
returns (uint256[] memory takerTokenAmounts)
{
_assertValidPair(makerToken, takerToken);
uint256 numSamples = makerTokenAmounts.length;
takerTokenAmounts = new uint256[](numSamples);
for (uint256 i = 0; i < numSamples; i++) {
try
IEth2Dai(router).getPayAmount
{gas: ETH2DAI_CALL_GAS}
(takerToken, makerToken, makerTokenAmounts[i])
returns (uint256 amount)
{
takerTokenAmounts[i] = amount;
// Break early if there are 0 amounts
if (takerTokenAmounts[i] == 0) {
break;
}
} catch (bytes memory) {
// Swallow failures, leaving all results as zero.
break;
}
}
}
}

View File

@ -1,42 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 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.6;
interface IEth2Dai {
function getBuyAmount(
address buyToken,
address payToken,
uint256 payAmount
)
external
view
returns (uint256 buyAmount);
function getPayAmount(
address payToken,
address buyToken,
uint256 buyAmount
)
external
view
returns (uint256 payAmount);
}

View File

@ -20,7 +20,6 @@ pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "../src/ERC20BridgeSampler.sol";
import "../src/interfaces/IEth2Dai.sol";
import "../src/interfaces/IKyberNetwork.sol";
import "../src/interfaces/IUniswapV2Router01.sol";
@ -379,54 +378,6 @@ contract TestERC20BridgeSamplerKyberNetwork is
}
contract TestERC20BridgeSamplerEth2Dai is
IEth2Dai,
FailTrigger
{
bytes32 constant private SALT = 0xb713b61bb9bb2958a0f5d1534b21e94fc68c4c0c034b0902ed844f2f6cd1b4f7;
// Deterministic `IEth2Dai.getBuyAmount()`.
function getBuyAmount(
address buyToken,
address payToken,
uint256 payAmount
)
override
external
view
returns (uint256 buyAmount)
{
_revertIfShouldFail();
return LibDeterministicQuotes.getDeterministicSellQuote(
SALT,
payToken,
buyToken,
payAmount
);
}
// Deterministic `IEth2Dai.getPayAmount()`.
function getPayAmount(
address payToken,
address buyToken,
uint256 buyAmount
)
override
external
view
returns (uint256 payAmount)
{
_revertIfShouldFail();
return LibDeterministicQuotes.getDeterministicBuyQuote(
SALT,
payToken,
buyToken,
buyAmount
);
}
}
contract TestERC20BridgeSamplerUniswapExchangeFactory is
IUniswapExchangeFactory
{
@ -461,7 +412,6 @@ contract TestERC20BridgeSampler is
{
TestERC20BridgeSamplerUniswapExchangeFactory public uniswap;
TestERC20BridgeSamplerUniswapV2Router01 public uniswapV2Router;
TestERC20BridgeSamplerEth2Dai public eth2Dai;
TestERC20BridgeSamplerKyberNetwork public kyber;
uint8 private constant MAX_ORDER_STATUS = uint8(IExchange.OrderStatus.CANCELLED) + 1;
@ -469,7 +419,6 @@ contract TestERC20BridgeSampler is
constructor() public ERC20BridgeSampler() {
uniswap = new TestERC20BridgeSamplerUniswapExchangeFactory();
uniswapV2Router = new TestERC20BridgeSamplerUniswapV2Router01();
eth2Dai = new TestERC20BridgeSamplerEth2Dai();
kyber = new TestERC20BridgeSamplerKyberNetwork();
}

View File

@ -39,7 +39,7 @@
"config": {
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2Sampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|FakeTaker|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|KyberSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SmoothySampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler).json",
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2Sampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|FakeTaker|IBalancer|IBancor|ICurve|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|KyberSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SmoothySampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler).json",
"postpublish": {
"assets": []
}
@ -63,7 +63,7 @@
"@0x/contract-addresses": "^6.6.0",
"@0x/contract-wrappers": "^13.17.4",
"@0x/contracts-erc20": "^3.3.16",
"@0x/contracts-zero-ex": "^0.28.0",
"@0x/contracts-zero-ex": "^0.27.0",
"@0x/dev-utils": "^4.2.7",
"@0x/json-schemas": "^6.1.3",
"@0x/protocol-utils": "^1.8.2",

View File

@ -377,6 +377,8 @@ export const MAINNET_TOKENS = {
FEI: '0x956f47f50a910163d8bf957cf5846d573e7f87ca',
DSU: '0x605d26fbd5be761089281d5cec2ce86eea667109',
ESS: '0x24ae124c4cc33d6791f8e8b63520ed7107ac8b3e',
cvxCRV: '0x62b9c7356a2dc64a1969e19c23e4f579f9810aa7',
CRV: '0xd533a949740bb3306d119cc777fa900ba034cd52',
};
export const BSC_TOKENS = {
@ -565,18 +567,21 @@ export const DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID = valueByChainId<string[]>(
[],
);
// Note be careful here as a UNION is performed when finding intermediary tokens
// attaching to a default intermediary token (stables or ETH etc) can have a large impact
export const DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID = valueByChainId<TokenAdjacencyGraph>(
{
[ChainId.Mainnet]: new TokenAdjacencyGraphBuilder({
default: DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID[ChainId.Mainnet],
})
// Mirror Protocol
.tap(builder => {
// Mirror Protocol
builder
.add(MAINNET_TOKENS.MIR, MAINNET_TOKENS.UST)
.add(MAINNET_TOKENS.UST, [MAINNET_TOKENS.MIR, ...Object.values(MIRROR_WRAPPED_TOKENS)])
.add(MAINNET_TOKENS.USDT, MAINNET_TOKENS.UST);
.add(MAINNET_TOKENS.UST, [MAINNET_TOKENS.MIR, ...Object.values(MIRROR_WRAPPED_TOKENS)]);
Object.values(MIRROR_WRAPPED_TOKENS).forEach(t => builder.add(t, MAINNET_TOKENS.UST));
// Convex and Curve
builder.add(MAINNET_TOKENS.cvxCRV, MAINNET_TOKENS.CRV).add(MAINNET_TOKENS.CRV, MAINNET_TOKENS.cvxCRV);
})
// Build
.build(),
@ -1266,11 +1271,7 @@ export const KYBER_DMM_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
export const MOONISWAP_REGISTRIES_BY_CHAIN_ID = valueByChainId(
{
[ChainId.Mainnet]: [
'0x71CD6666064C3A1354a3B4dca5fA1E2D3ee7D303',
'0xc4a8b7e29e3c8ec560cd4945c1cf3461a85a148d',
'0xbaf9a5d4b0052359326a6cdab54babaa3a3a9643',
],
[ChainId.Mainnet]: ['0xbaf9a5d4b0052359326a6cdab54babaa3a3a9643'],
[ChainId.BSC]: ['0xd41b24bba51fac0e4827b6f94c0d6ddeb183cd64'],
},
[] as string[],

View File

@ -22,7 +22,7 @@ export function getIntermediateTokens(
takerToken: string,
tokenAdjacencyGraph: TokenAdjacencyGraph,
): string[] {
const intermediateTokens = _.intersection(
const intermediateTokens = _.union(
_.get(tokenAdjacencyGraph, takerToken, tokenAdjacencyGraph.default),
_.get(tokenAdjacencyGraph, makerToken, tokenAdjacencyGraph.default),
);

View File

@ -84,19 +84,11 @@ export class Path {
* not present in this path
*/
public addFallback(fallback: Path): this {
// If the last fill is Native and penultimate is not, then the intention was to partial fill
// In this case we drop it entirely as we can't handle a failure at the end and we don't
// want to fully fill when it gets prepended to the front below
const [last, penultimateIfExists] = this.fills.slice().reverse();
const lastNativeFillIfExists =
last.source === ERC20BridgeSource.Native &&
penultimateIfExists &&
penultimateIfExists.source !== ERC20BridgeSource.Native
? last
: undefined;
// By prepending native paths to the front they cannot split on-chain sources and incur
// an additional protocol fee. I.e [Uniswap,Native,Kyber] becomes [Native,Uniswap,Kyber]
// In the previous step we dropped any hanging Native partial fills, as to not fully fill
// We pre-pend the sources which have a higher probability of failure
// This allows us to continue on to the remaining fills
// If the "flakey" sources like Native were at the end, we may have a failure
// as the last fill and then either revert, or go back to a source we previously
// filled against
const nativeFills = this.fills.filter(f => f.source === ERC20BridgeSource.Native);
const otherFills = this.fills.filter(f => f.source !== ERC20BridgeSource.Native);
@ -106,7 +98,7 @@ export class Path {
this.fills = [
// Append all of the native fills first
...nativeFills.filter(f => f !== lastNativeFillIfExists),
...nativeFills,
// Add the other fills that are not native in the optimal path
...otherFills,
// Add the fills to the end that aren't already included

View File

@ -35,7 +35,6 @@ import {
NATIVE_FEE_TOKEN_BY_CHAIN_ID,
NULL_ADDRESS,
NULL_BYTES,
OASIS_ROUTER_BY_CHAIN_ID,
SELL_SOURCE_FILTER_BY_CHAIN_ID,
UNISWAPV1_ROUTER_BY_CHAIN_ID,
UNISWAPV3_CONFIG_BY_CHAIN_ID,
@ -394,36 +393,6 @@ export class SamplerOperations {
});
}
public getEth2DaiSellQuotes(
router: string,
makerToken: string,
takerToken: string,
takerFillAmounts: BigNumber[],
): SourceQuoteOperation<GenericRouterFillData> {
return new SamplerContractOperation({
source: ERC20BridgeSource.Eth2Dai,
fillData: { router },
contract: this._samplerContract,
function: this._samplerContract.sampleSellsFromEth2Dai,
params: [router, takerToken, makerToken, takerFillAmounts],
});
}
public getEth2DaiBuyQuotes(
router: string,
makerToken: string,
takerToken: string,
makerFillAmounts: BigNumber[],
): SourceQuoteOperation<GenericRouterFillData> {
return new SamplerContractOperation({
source: ERC20BridgeSource.Eth2Dai,
fillData: { router },
contract: this._samplerContract,
function: this._samplerContract.sampleBuysFromEth2Dai,
params: [router, takerToken, makerToken, makerFillAmounts],
});
}
public getCurveSellQuotes(
pool: CurveInfo,
fromTokenIdx: number,
@ -1200,14 +1169,7 @@ export class SamplerOperations {
}
switch (source) {
case ERC20BridgeSource.Eth2Dai:
return isValidAddress(OASIS_ROUTER_BY_CHAIN_ID[this.chainId])
? this.getEth2DaiSellQuotes(
OASIS_ROUTER_BY_CHAIN_ID[this.chainId],
makerToken,
takerToken,
takerFillAmounts,
)
: [];
return [];
case ERC20BridgeSource.Uniswap:
return isValidAddress(UNISWAPV1_ROUTER_BY_CHAIN_ID[this.chainId])
? this.getUniswapSellQuotes(
@ -1500,14 +1462,7 @@ export class SamplerOperations {
_sources.map((source): SourceQuoteOperation | SourceQuoteOperation[] => {
switch (source) {
case ERC20BridgeSource.Eth2Dai:
return isValidAddress(OASIS_ROUTER_BY_CHAIN_ID[this.chainId])
? this.getEth2DaiBuyQuotes(
OASIS_ROUTER_BY_CHAIN_ID[this.chainId],
makerToken,
takerToken,
makerFillAmounts,
)
: [];
return [];
case ERC20BridgeSource.Uniswap:
return isValidAddress(UNISWAPV1_ROUTER_BY_CHAIN_ID[this.chainId])
? this.getUniswapBuyQuotes(

View File

@ -15,12 +15,10 @@ import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json';
import * as DODOV2Sampler from '../test/generated-artifacts/DODOV2Sampler.json';
import * as DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquidityProvider.json';
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
import * as Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json';
import * as FakeTaker from '../test/generated-artifacts/FakeTaker.json';
import * as IBalancer from '../test/generated-artifacts/IBalancer.json';
import * as IBancor from '../test/generated-artifacts/IBancor.json';
import * as ICurve from '../test/generated-artifacts/ICurve.json';
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json';
import * as IMStable from '../test/generated-artifacts/IMStable.json';
@ -58,7 +56,6 @@ export const artifacts = {
DODOSampler: DODOSampler as ContractArtifact,
DODOV2Sampler: DODOV2Sampler as ContractArtifact,
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
Eth2DaiSampler: Eth2DaiSampler as ContractArtifact,
FakeTaker: FakeTaker as ContractArtifact,
KyberDmmSampler: KyberDmmSampler as ContractArtifact,
KyberSampler: KyberSampler as ContractArtifact,
@ -80,7 +77,6 @@ export const artifacts = {
IBalancer: IBalancer as ContractArtifact,
IBancor: IBancor as ContractArtifact,
ICurve: ICurve as ContractArtifact,
IEth2Dai: IEth2Dai as ContractArtifact,
IKyberNetwork: IKyberNetwork as ContractArtifact,
IMStable: IMStable as ContractArtifact,
IMooniswap: IMooniswap as ContractArtifact,

View File

@ -27,7 +27,6 @@ blockchainTests('erc20-bridge-sampler', env => {
const MAX_DECIMALS = 20;
const WETH_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
const KYBER_SALT = '0x0ff3ca9d46195c39f9a12afb74207b4970349fb3cfb1e459bbf170298d326bc7';
const ETH2DAI_SALT = '0xb713b61bb9bb2958a0f5d1534b21e94fc68c4c0c034b0902ed844f2f6cd1b4f7';
const UNISWAP_BASE_SALT = '0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab';
const UNISWAP_V2_SALT = '0xadc7fcb33c735913b8635927e66896b356a53a912ab2ceff929e60a04b53b3c1';
const INVALID_TOKEN_PAIR_ERROR = 'ERC20BridgeSampler/INVALID_TOKEN_PAIR';
@ -36,7 +35,6 @@ blockchainTests('erc20-bridge-sampler', env => {
const INTERMEDIATE_TOKEN = randomAddress();
const KYBER_RESERVE_OFFSET = new BigNumber(0);
let KYBER_ADDRESS = '';
let ETH2DAI_ADDRESS = '';
let UNISWAP_ADDRESS = '';
let UNISWAP_V2_ROUTER = '';
@ -49,7 +47,6 @@ blockchainTests('erc20-bridge-sampler', env => {
);
UNISWAP_V2_ROUTER = await testContract.uniswapV2Router().callAsync();
KYBER_ADDRESS = await testContract.kyber().callAsync();
ETH2DAI_ADDRESS = await testContract.eth2Dai().callAsync();
UNISWAP_ADDRESS = await testContract.uniswap().callAsync();
});
@ -152,15 +149,8 @@ blockchainTests('erc20-bridge-sampler', env => {
for (const source of sources) {
const sampleOutputs = [];
for (const amount of sampleAmounts) {
if (source === 'Kyber' || source === 'Eth2Dai') {
sampleOutputs.push(
getDeterministicSellQuote(
source === 'Kyber' ? KYBER_SALT : ETH2DAI_SALT,
sellToken,
buyToken,
amount,
),
);
if (source === 'Kyber') {
sampleOutputs.push(getDeterministicSellQuote(KYBER_SALT, sellToken, buyToken, amount));
} else if (source === 'Uniswap') {
sampleOutputs.push(getDeterministicUniswapSellQuote(sellToken, buyToken, amount));
}
@ -180,15 +170,8 @@ blockchainTests('erc20-bridge-sampler', env => {
for (const source of sources) {
const sampleOutputs = [];
for (const amount of sampleAmounts) {
if (source === 'Kyber' || source === 'Eth2Dai') {
sampleOutputs.push(
getDeterministicBuyQuote(
source === 'Kyber' ? KYBER_SALT : ETH2DAI_SALT,
sellToken,
buyToken,
amount,
),
);
if (source === 'Kyber') {
sampleOutputs.push(getDeterministicBuyQuote(KYBER_SALT, sellToken, buyToken, amount));
} else if (source === 'Uniswap') {
sampleOutputs.push(getDeterministicUniswapBuyQuote(sellToken, buyToken, amount));
}
@ -510,156 +493,6 @@ blockchainTests('erc20-bridge-sampler', env => {
});
});
blockchainTests.resets('sampleSellsFromEth2Dai()', () => {
before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
});
it('throws if tokens are the same', async () => {
const tx = testContract.sampleSellsFromEth2Dai(ETH2DAI_ADDRESS, MAKER_TOKEN, MAKER_TOKEN, []).callAsync();
return expect(tx).to.revertWith(INVALID_TOKEN_PAIR_ERROR);
});
it('can return no quotes', async () => {
const quotes = await testContract
.sampleSellsFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, MAKER_TOKEN, [])
.callAsync();
expect(quotes).to.deep.eq([]);
});
it('can quote token -> token', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
const quotes = await testContract
.sampleSellsFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> token fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote token -> ETH', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Eth2Dai'], sampleAmounts);
const quotes = await testContract
.sampleSellsFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> ETH fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote ETH -> token', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
const quotes = await testContract
.sampleSellsFromEth2Dai(ETH2DAI_ADDRESS, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if ETH -> token fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromEth2Dai(ETH2DAI_ADDRESS, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
});
blockchainTests.resets('sampleBuysFromEth2Dai()', () => {
before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
});
it('throws if tokens are the same', async () => {
const tx = testContract.sampleBuysFromEth2Dai(ETH2DAI_ADDRESS, MAKER_TOKEN, MAKER_TOKEN, []).callAsync();
return expect(tx).to.revertWith(INVALID_TOKEN_PAIR_ERROR);
});
it('can return no quotes', async () => {
const quotes = await testContract
.sampleBuysFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, MAKER_TOKEN, [])
.callAsync();
expect(quotes).to.deep.eq([]);
});
it('can quote token -> token', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
const quotes = await testContract
.sampleBuysFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> token fails', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleBuysFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote token -> ETH', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Eth2Dai'], sampleAmounts);
const quotes = await testContract
.sampleBuysFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> ETH fails', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleBuysFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote ETH -> token', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const [expectedQuotes] = getDeterministicBuyQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
const quotes = await testContract
.sampleBuysFromEth2Dai(ETH2DAI_ADDRESS, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if ETH -> token fails', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleBuysFromEth2Dai(ETH2DAI_ADDRESS, WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
});
blockchainTests.resets('sampleSellsFromUniswap()', () => {
const UNISWAP_ETH_ADDRESS = NULL_ADDRESS;
before(async () => {
@ -1094,35 +927,15 @@ blockchainTests('erc20-bridge-sampler', env => {
.sampleSellsFromUniswapV2(UNISWAP_V2_ROUTER, uniswapV2SecondHopPath, [constants.ZERO_AMOUNT])
.getABIEncodedTransactionData();
const eth2DaiFirstHop = testContract
.sampleSellsFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, INTERMEDIATE_TOKEN, [constants.ZERO_AMOUNT])
.getABIEncodedTransactionData();
const eth2DaiSecondHop = testContract
.sampleSellsFromEth2Dai(ETH2DAI_ADDRESS, INTERMEDIATE_TOKEN, MAKER_TOKEN, [constants.ZERO_AMOUNT])
.getABIEncodedTransactionData();
const firstHopQuotes = [
getDeterministicSellQuote(ETH2DAI_SALT, TAKER_TOKEN, INTERMEDIATE_TOKEN, sellAmount),
getDeterministicUniswapV2SellQuote(uniswapV2FirstHopPath, sellAmount),
];
const firstHopQuotes = [getDeterministicUniswapV2SellQuote(uniswapV2FirstHopPath, sellAmount)];
const expectedIntermediateAssetAmount = BigNumber.max(...firstHopQuotes);
const secondHopQuotes = [
getDeterministicSellQuote(
ETH2DAI_SALT,
INTERMEDIATE_TOKEN,
MAKER_TOKEN,
expectedIntermediateAssetAmount,
),
getDeterministicUniswapV2SellQuote(uniswapV2SecondHopPath, expectedIntermediateAssetAmount),
];
const expectedBuyAmount = BigNumber.max(...secondHopQuotes);
const [firstHop, secondHop, buyAmount] = await testContract
.sampleTwoHopSell(
[eth2DaiFirstHop, uniswapV2FirstHop],
[eth2DaiSecondHop, uniswapV2SecondHop],
sellAmount,
)
.sampleTwoHopSell([uniswapV2FirstHop], [uniswapV2SecondHop], sellAmount)
.callAsync();
expect(firstHop.sourceIndex, 'First hop source index').to.bignumber.equal(
firstHopQuotes.findIndex(quote => quote.isEqualTo(expectedIntermediateAssetAmount)),
@ -1145,36 +958,16 @@ blockchainTests('erc20-bridge-sampler', env => {
.sampleBuysFromUniswapV2(UNISWAP_V2_ROUTER, uniswapV2SecondHopPath, [constants.ZERO_AMOUNT])
.getABIEncodedTransactionData();
const eth2DaiFirstHop = testContract
.sampleBuysFromEth2Dai(ETH2DAI_ADDRESS, TAKER_TOKEN, INTERMEDIATE_TOKEN, [constants.ZERO_AMOUNT])
.getABIEncodedTransactionData();
const eth2DaiSecondHop = testContract
.sampleBuysFromEth2Dai(ETH2DAI_ADDRESS, INTERMEDIATE_TOKEN, MAKER_TOKEN, [constants.ZERO_AMOUNT])
.getABIEncodedTransactionData();
const secondHopQuotes = [
getDeterministicBuyQuote(ETH2DAI_SALT, INTERMEDIATE_TOKEN, MAKER_TOKEN, buyAmount),
getDeterministicUniswapV2BuyQuote(uniswapV2SecondHopPath, buyAmount),
];
const secondHopQuotes = [getDeterministicUniswapV2BuyQuote(uniswapV2SecondHopPath, buyAmount)];
const expectedIntermediateAssetAmount = BigNumber.min(...secondHopQuotes);
const firstHopQuotes = [
getDeterministicBuyQuote(
ETH2DAI_SALT,
TAKER_TOKEN,
INTERMEDIATE_TOKEN,
expectedIntermediateAssetAmount,
),
getDeterministicUniswapV2BuyQuote(uniswapV2FirstHopPath, expectedIntermediateAssetAmount),
];
const expectedSellAmount = BigNumber.min(...firstHopQuotes);
const [firstHop, secondHop, sellAmount] = await testContract
.sampleTwoHopBuy(
[eth2DaiFirstHop, uniswapV2FirstHop],
[eth2DaiSecondHop, uniswapV2SecondHop],
buyAmount,
)
.sampleTwoHopBuy([uniswapV2FirstHop], [uniswapV2SecondHop], buyAmount)
.callAsync();
expect(firstHop.sourceIndex, 'First hop source index').to.bignumber.equal(
firstHopQuotes.findIndex(quote => quote.isEqualTo(expectedSellAmount)),

View File

@ -264,39 +264,6 @@ describe('DexSampler tests', () => {
]);
});
it('getEth2DaiSellQuotes()', async () => {
const expectedTakerToken = randomAddress();
const expectedMakerToken = randomAddress();
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
const sampler = new MockSamplerContract({
sampleSellsFromEth2Dai: (_router, takerToken, makerToken, fillAmounts) => {
expect(takerToken).to.eq(expectedTakerToken);
expect(makerToken).to.eq(expectedMakerToken);
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
return expectedMakerFillAmounts;
},
});
const dexOrderSampler = new DexOrderSampler(
chainId,
sampler,
undefined,
undefined,
undefined,
undefined,
async () => undefined,
);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
dexOrderSampler.getEth2DaiSellQuotes(
randomAddress(),
expectedMakerToken,
expectedTakerToken,
expectedTakerFillAmounts,
),
);
expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts);
});
it('getUniswapSellQuotes()', async () => {
const expectedTakerToken = randomAddress();
const expectedMakerToken = randomAddress();
@ -361,39 +328,6 @@ describe('DexSampler tests', () => {
expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts);
});
it('getEth2DaiBuyQuotes()', async () => {
const expectedTakerToken = randomAddress();
const expectedMakerToken = randomAddress();
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
const sampler = new MockSamplerContract({
sampleBuysFromEth2Dai: (_router, takerToken, makerToken, fillAmounts) => {
expect(takerToken).to.eq(expectedTakerToken);
expect(makerToken).to.eq(expectedMakerToken);
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
return expectedTakerFillAmounts;
},
});
const dexOrderSampler = new DexOrderSampler(
chainId,
sampler,
undefined,
undefined,
undefined,
undefined,
async () => undefined,
);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
dexOrderSampler.getEth2DaiBuyQuotes(
randomAddress(),
expectedMakerToken,
expectedTakerToken,
expectedMakerFillAmounts,
),
);
expect(fillableAmounts).to.deep.eq(expectedTakerFillAmounts);
});
it('getUniswapBuyQuotes()', async () => {
const expectedTakerToken = randomAddress();
const expectedMakerToken = randomAddress();
@ -434,17 +368,15 @@ describe('DexSampler tests', () => {
it('getSellQuotes()', async () => {
const expectedTakerToken = randomAddress();
const expectedMakerToken = randomAddress();
const sources = [ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Uniswap, ERC20BridgeSource.UniswapV2];
const sources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.UniswapV2];
const ratesBySource: RatesBySource = {
[ERC20BridgeSource.Kyber]: getRandomFloat(0, 100),
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
[ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100),
[ERC20BridgeSource.UniswapV2]: getRandomFloat(0, 100),
};
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
let uniswapRouter: string;
let uniswapV2Router: string;
let eth2DaiRouter: string;
const sampler = new MockSamplerContract({
sampleSellsFromUniswap: (router, takerToken, makerToken, fillAmounts) => {
uniswapRouter = router;
@ -453,13 +385,6 @@ describe('DexSampler tests', () => {
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Uniswap]).integerValue());
},
sampleSellsFromEth2Dai: (router, takerToken, makerToken, fillAmounts) => {
eth2DaiRouter = router;
expect(takerToken).to.eq(expectedTakerToken);
expect(makerToken).to.eq(expectedMakerToken);
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Eth2Dai]).integerValue());
},
sampleSellsFromUniswapV2: (router, path, fillAmounts) => {
uniswapV2Router = router;
if (path.length === 2) {
@ -502,9 +427,6 @@ describe('DexSampler tests', () => {
tokenAddressPath: [expectedTakerToken, expectedMakerToken],
};
}
if (s === ERC20BridgeSource.Eth2Dai) {
return { router: eth2DaiRouter };
}
// TODO jacob pass through
if (s === ERC20BridgeSource.Uniswap) {
return { router: uniswapRouter };
@ -532,16 +454,14 @@ describe('DexSampler tests', () => {
it('getBuyQuotes()', async () => {
const expectedTakerToken = randomAddress();
const expectedMakerToken = randomAddress();
const sources = [ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Uniswap, ERC20BridgeSource.UniswapV2];
const sources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.UniswapV2];
const ratesBySource: RatesBySource = {
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
[ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100),
[ERC20BridgeSource.UniswapV2]: getRandomFloat(0, 100),
};
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
let uniswapRouter: string;
let uniswapV2Router: string;
let eth2DaiRouter: string;
const sampler = new MockSamplerContract({
sampleBuysFromUniswap: (router, takerToken, makerToken, fillAmounts) => {
uniswapRouter = router;
@ -550,13 +470,6 @@ describe('DexSampler tests', () => {
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Uniswap]).integerValue());
},
sampleBuysFromEth2Dai: (router, takerToken, makerToken, fillAmounts) => {
eth2DaiRouter = router;
expect(takerToken).to.eq(expectedTakerToken);
expect(makerToken).to.eq(expectedMakerToken);
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Eth2Dai]).integerValue());
},
sampleBuysFromUniswapV2: (router, path, fillAmounts) => {
uniswapV2Router = router;
if (path.length === 2) {
@ -594,9 +507,6 @@ describe('DexSampler tests', () => {
tokenAddressPath: [expectedTakerToken, expectedMakerToken],
};
}
if (s === ERC20BridgeSource.Eth2Dai) {
return { router: eth2DaiRouter };
}
if (s === ERC20BridgeSource.Uniswap) {
return { router: uniswapRouter };
}

View File

@ -53,26 +53,6 @@ describe('Path', () => {
]);
});
it('Removes partial Native orders', () => {
const targetInput = new BigNumber(100);
const path = Path.create(
MarketOperation.Sell,
[
createFill(ERC20BridgeSource.Uniswap),
createFill(ERC20BridgeSource.LiquidityProvider),
createFill(ERC20BridgeSource.Native),
],
targetInput,
);
const fallback = Path.create(MarketOperation.Sell, [createFill(ERC20BridgeSource.Kyber)], targetInput);
path.addFallback(fallback);
const sources = path.fills.map(f => f.source);
expect(sources).to.deep.eq([
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.LiquidityProvider,
ERC20BridgeSource.Kyber,
]);
});
it('Handles duplicates', () => {
const targetInput = new BigNumber(100);
const path = Path.create(
@ -85,7 +65,7 @@ describe('Path', () => {
const sources = path.fills.map(f => f.source);
expect(sources).to.deep.eq([ERC20BridgeSource.Uniswap, ERC20BridgeSource.LiquidityProvider]);
});
it('Removes partial Native orders and replaces with unused fills', () => {
it('Moves Native orders to the front and appends with unused fills', () => {
const targetInput = new BigNumber(100);
const path = Path.create(
MarketOperation.Sell,
@ -105,6 +85,6 @@ describe('Path', () => {
);
path.addFallback(fallback);
const sources = path.fills.map(f => f.source);
expect(sources).to.deep.eq([ERC20BridgeSource.Uniswap, ERC20BridgeSource.Uniswap]);
expect(sources).to.deep.eq([ERC20BridgeSource.Native, ERC20BridgeSource.Uniswap, ERC20BridgeSource.Uniswap]);
});
});

View File

@ -72,10 +72,8 @@ interface Handlers {
getLimitOrderFillableTakerAssetAmounts: GetOrderFillableAssetAmountHandler;
sampleSellsFromKyberNetwork: SampleSellsKyberHandler;
sampleSellsFromLiquidityProvider: SampleSellsLPHandler;
sampleSellsFromEth2Dai: SampleSellsEth2DaiHandler;
sampleSellsFromUniswap: SampleSellsUniswapHandler;
sampleSellsFromUniswapV2: SampleUniswapV2Handler;
sampleBuysFromEth2Dai: SampleBuysEth2DaiHandler;
sampleBuysFromUniswap: SampleBuysUniswapHandler;
sampleBuysFromUniswapV2: SampleUniswapV2Handler;
sampleBuysFromLiquidityProvider: SampleSellsLPHandler;
@ -141,22 +139,6 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract {
);
}
public sampleSellsFromEth2Dai(
router: string,
takerToken: string,
makerToken: string,
takerAssetAmounts: BigNumber[],
): ContractTxFunctionObj<BigNumber[]> {
return this._wrapCall(
super.sampleSellsFromEth2Dai,
this._handlers.sampleSellsFromEth2Dai,
router,
takerToken,
makerToken,
takerAssetAmounts,
);
}
public sampleSellsFromUniswap(
router: string,
takerToken: string,
@ -203,22 +185,6 @@ export class MockSamplerContract extends ERC20BridgeSamplerContract {
);
}
public sampleBuysFromEth2Dai(
router: string,
takerToken: string,
makerToken: string,
makerAssetAmounts: BigNumber[],
): ContractTxFunctionObj<BigNumber[]> {
return this._wrapCall(
super.sampleBuysFromEth2Dai,
this._handlers.sampleBuysFromEth2Dai,
router,
takerToken,
makerToken,
makerAssetAmounts,
);
}
public sampleBuysFromUniswap(
router: string,
takerToken: string,

View File

@ -13,12 +13,10 @@ export * from '../test/generated-wrappers/d_o_d_o_sampler';
export * from '../test/generated-wrappers/d_o_d_o_v2_sampler';
export * from '../test/generated-wrappers/dummy_liquidity_provider';
export * from '../test/generated-wrappers/erc20_bridge_sampler';
export * from '../test/generated-wrappers/eth2_dai_sampler';
export * from '../test/generated-wrappers/fake_taker';
export * from '../test/generated-wrappers/i_balancer';
export * from '../test/generated-wrappers/i_bancor';
export * from '../test/generated-wrappers/i_curve';
export * from '../test/generated-wrappers/i_eth2_dai';
export * from '../test/generated-wrappers/i_kyber_network';
export * from '../test/generated-wrappers/i_m_stable';
export * from '../test/generated-wrappers/i_mooniswap';

View File

@ -16,12 +16,10 @@
"test/generated-artifacts/DODOV2Sampler.json",
"test/generated-artifacts/DummyLiquidityProvider.json",
"test/generated-artifacts/ERC20BridgeSampler.json",
"test/generated-artifacts/Eth2DaiSampler.json",
"test/generated-artifacts/FakeTaker.json",
"test/generated-artifacts/IBalancer.json",
"test/generated-artifacts/IBancor.json",
"test/generated-artifacts/ICurve.json",
"test/generated-artifacts/IEth2Dai.json",
"test/generated-artifacts/IKyberNetwork.json",
"test/generated-artifacts/IMStable.json",
"test/generated-artifacts/IMooniswap.json",

186
yarn.lock
View File

@ -704,33 +704,15 @@
js-sha3 "^0.7.0"
uuid "^3.3.2"
"@0x/contract-addresses@^6.6.0":
version "6.6.0"
resolved "https://registry.yarnpkg.com/@0x/contract-addresses/-/contract-addresses-6.6.0.tgz#8525697a02a765e998211fb45814b4247ce7d820"
"@0x/contract-wrappers@^13.17.4":
version "13.17.4"
resolved "https://registry.yarnpkg.com/@0x/contract-wrappers/-/contract-wrappers-13.17.4.tgz#79c4964705e0a6d6eef8312901d897c13a7977e9"
dependencies:
"@0x/assert" "^3.0.27"
"@0x/base-contract" "^6.4.0"
"@0x/contract-addresses" "^6.6.0"
"@0x/json-schemas" "^6.1.3"
"@0x/types" "^3.3.3"
"@0x/utils" "^6.4.3"
"@0x/web3-wrapper" "^7.5.3"
ethereum-types "^3.5.0"
ethers "~4.0.4"
"@0x/contracts-asset-proxy@^3.7.17":
version "3.7.18"
resolved "https://registry.yarnpkg.com/@0x/contracts-asset-proxy/-/contracts-asset-proxy-3.7.18.tgz#d0a031ccf32d3266b5ec86c07f538b3fbb66ccc1"
"@0x/contracts-asset-proxy@^3.7.19":
version "3.7.19"
resolved "https://registry.yarnpkg.com/@0x/contracts-asset-proxy/-/contracts-asset-proxy-3.7.19.tgz#ee621a233f4d77b439c74c5b8d70db2e1ed001c4"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/contracts-erc1155" "^2.1.36"
"@0x/contracts-erc20" "^3.3.15"
"@0x/contracts-erc721" "^3.1.36"
"@0x/contracts-exchange-libs" "^4.3.36"
"@0x/contracts-erc1155" "^2.1.37"
"@0x/contracts-erc20" "^3.3.16"
"@0x/contracts-erc721" "^3.1.37"
"@0x/contracts-exchange-libs" "^4.3.37"
"@0x/order-utils" "^10.4.28"
"@0x/types" "^3.3.3"
"@0x/typescript-typings" "^5.2.0"
@ -739,16 +721,16 @@
ethereum-types "^3.5.0"
lodash "^4.17.11"
"@0x/contracts-coordinator@^3.1.36":
version "3.1.36"
resolved "https://registry.yarnpkg.com/@0x/contracts-coordinator/-/contracts-coordinator-3.1.36.tgz#fad0ce622546365498c5b5a8033154a571386162"
"@0x/contracts-coordinator@^3.1.38":
version "3.1.38"
resolved "https://registry.yarnpkg.com/@0x/contracts-coordinator/-/contracts-coordinator-3.1.38.tgz#88988c104bc8e987675c441a305073f1376f257b"
dependencies:
"@0x/assert" "^3.0.27"
"@0x/base-contract" "^6.4.0"
"@0x/contract-addresses" "^6.5.0"
"@0x/contracts-exchange" "^3.2.36"
"@0x/contracts-test-utils" "^5.4.6"
"@0x/contracts-utils" "^4.7.14"
"@0x/contract-addresses" "^6.6.0"
"@0x/contracts-exchange" "^3.2.38"
"@0x/contracts-test-utils" "^5.4.8"
"@0x/contracts-utils" "^4.7.16"
"@0x/json-schemas" "^6.1.3"
"@0x/types" "^3.3.3"
"@0x/typescript-typings" "^5.2.0"
@ -756,92 +738,69 @@
ethereum-types "^3.5.0"
http-status-codes "^1.3.2"
"@0x/contracts-dev-utils@^1.3.34":
version "1.3.34"
resolved "https://registry.yarnpkg.com/@0x/contracts-dev-utils/-/contracts-dev-utils-1.3.34.tgz#be755bb5a6da75c3e06887a3d0c5159ca7f1468c"
"@0x/contracts-dev-utils@^1.3.36":
version "1.3.36"
resolved "https://registry.yarnpkg.com/@0x/contracts-dev-utils/-/contracts-dev-utils-1.3.36.tgz#f29304a0d7375001165ef6e66695d14b6a153fd7"
dependencies:
"@0x/base-contract" "^6.4.0"
"@types/node" "12.12.54"
"@0x/contracts-erc1155@^2.1.35":
version "2.1.35"
resolved "https://registry.yarnpkg.com/@0x/contracts-erc1155/-/contracts-erc1155-2.1.35.tgz#a3e2ce36b428b8b9b21c41afc6ef2817081b9f4e"
"@0x/contracts-erc1155@^2.1.37":
version "2.1.37"
resolved "https://registry.yarnpkg.com/@0x/contracts-erc1155/-/contracts-erc1155-2.1.37.tgz#98dc158ffd00f80771e4232ed2a5246ab4ab73c1"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/contracts-test-utils" "^5.4.6"
"@0x/contracts-test-utils" "^5.4.8"
"@0x/utils" "^6.4.3"
"@0x/web3-wrapper" "^7.5.3"
lodash "^4.17.11"
"@0x/contracts-erc1155@^2.1.36":
version "2.1.36"
resolved "https://registry.yarnpkg.com/@0x/contracts-erc1155/-/contracts-erc1155-2.1.36.tgz#ed744dc6f947e2cd82b10758316c7aeb75d1322b"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/contracts-test-utils" "^5.4.7"
"@0x/utils" "^6.4.3"
"@0x/web3-wrapper" "^7.5.3"
lodash "^4.17.11"
"@0x/contracts-erc20@^3.3.15":
version "3.3.15"
resolved "https://registry.yarnpkg.com/@0x/contracts-erc20/-/contracts-erc20-3.3.15.tgz#386c4ea50f64399e46e1b4de0d8a6186a6be2410"
dependencies:
"@0x/base-contract" "^6.4.0"
ethers "~4.0.4"
"@0x/contracts-erc721@^3.1.35":
version "3.1.35"
resolved "https://registry.yarnpkg.com/@0x/contracts-erc721/-/contracts-erc721-3.1.35.tgz#de9d7ddce0708f1262e724757b8d7e7785cd0e84"
"@0x/contracts-erc721@^3.1.37":
version "3.1.37"
resolved "https://registry.yarnpkg.com/@0x/contracts-erc721/-/contracts-erc721-3.1.37.tgz#d7d356737e3d2752cf49be385237fbf7d0c5745c"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/contracts-erc721@^3.1.36":
version "3.1.36"
resolved "https://registry.yarnpkg.com/@0x/contracts-erc721/-/contracts-erc721-3.1.36.tgz#fd858757f36e9c2b6698f3ae0883395895c1ac93"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/contracts-exchange-forwarder@^4.2.36":
version "4.2.36"
resolved "https://registry.yarnpkg.com/@0x/contracts-exchange-forwarder/-/contracts-exchange-forwarder-4.2.36.tgz#396416b7aa5b4e95d9af601fde8c88087f780c78"
"@0x/contracts-exchange-forwarder@^4.2.38":
version "4.2.38"
resolved "https://registry.yarnpkg.com/@0x/contracts-exchange-forwarder/-/contracts-exchange-forwarder-4.2.38.tgz#ba7ae06012ca526043c7c477851cff72405e80b1"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/typescript-typings" "^5.2.0"
ethereum-types "^3.5.0"
"@0x/contracts-exchange-libs@^4.3.35", "@0x/contracts-exchange-libs@^4.3.36":
version "4.3.36"
resolved "https://registry.yarnpkg.com/@0x/contracts-exchange-libs/-/contracts-exchange-libs-4.3.36.tgz#7bf7a01a68886d901850be39af5612cd0713e205"
"@0x/contracts-exchange-libs@^4.3.37":
version "4.3.37"
resolved "https://registry.yarnpkg.com/@0x/contracts-exchange-libs/-/contracts-exchange-libs-4.3.37.tgz#9413f76c77f8ec5231f21896a0e9f47cebe38680"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/contracts-test-utils" "^5.4.7"
"@0x/contracts-utils" "^4.7.15"
"@0x/contracts-test-utils" "^5.4.8"
"@0x/contracts-utils" "^4.7.16"
"@0x/order-utils" "^10.4.28"
"@0x/types" "^3.3.3"
"@0x/typescript-typings" "^5.2.0"
"@0x/utils" "^6.4.3"
ethereum-types "^3.5.0"
"@0x/contracts-exchange@^3.2.36":
version "3.2.36"
resolved "https://registry.yarnpkg.com/@0x/contracts-exchange/-/contracts-exchange-3.2.36.tgz#3b014d196ee65c37563a1ad8687800845acd712c"
"@0x/contracts-exchange@^3.2.38":
version "3.2.38"
resolved "https://registry.yarnpkg.com/@0x/contracts-exchange/-/contracts-exchange-3.2.38.tgz#51b12882283c816eebdb53f1c77805956112dfee"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/contracts-dev-utils" "^1.3.34"
"@0x/contracts-erc1155" "^2.1.35"
"@0x/contracts-erc20" "^3.3.14"
"@0x/contracts-erc721" "^3.1.35"
"@0x/order-utils" "^10.4.27"
"@0x/contracts-dev-utils" "^1.3.36"
"@0x/contracts-erc1155" "^2.1.37"
"@0x/contracts-erc20" "^3.3.16"
"@0x/contracts-erc721" "^3.1.37"
"@0x/order-utils" "^10.4.28"
"@0x/utils" "^6.4.3"
lodash "^4.17.11"
"@0x/contracts-extensions@^6.2.30":
version "6.2.30"
resolved "https://registry.yarnpkg.com/@0x/contracts-extensions/-/contracts-extensions-6.2.30.tgz#75d81234f4b2c3236a7c6a024ce60d8ebe9209fb"
"@0x/contracts-extensions@^6.2.32":
version "6.2.32"
resolved "https://registry.yarnpkg.com/@0x/contracts-extensions/-/contracts-extensions-6.2.32.tgz#2a2e3cad5a5b69f2aa0e6b62513b2b1acfe421f0"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/contracts-test-utils" "^5.4.6"
"@0x/contracts-test-utils" "^5.4.8"
"@0x/typescript-typings" "^5.2.0"
ethereum-types "^3.5.0"
@ -861,71 +820,38 @@
prettier "^1.16.3"
to-snake-case "^1.0.0"
"@0x/contracts-multisig@^4.1.36":
version "4.1.37"
resolved "https://registry.yarnpkg.com/@0x/contracts-multisig/-/contracts-multisig-4.1.37.tgz#081cacf4217cf50202ddb5ecdb41a47695b41cb2"
"@0x/contracts-multisig@^4.1.38":
version "4.1.38"
resolved "https://registry.yarnpkg.com/@0x/contracts-multisig/-/contracts-multisig-4.1.38.tgz#e4357b45fe3d4c56bff144fb267d0bb95b8eb46b"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/typescript-typings" "^5.2.0"
ethereum-types "^3.5.0"
"@0x/contracts-staking@^2.0.43":
version "2.0.44"
resolved "https://registry.yarnpkg.com/@0x/contracts-staking/-/contracts-staking-2.0.44.tgz#8bfca27012e44e281cb0acc02da5549bfd32919c"
"@0x/contracts-staking@^2.0.45":
version "2.0.45"
resolved "https://registry.yarnpkg.com/@0x/contracts-staking/-/contracts-staking-2.0.45.tgz#48a495d7ab1240cb4859e7a2ae6c1c78511bb6ed"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/contracts-test-utils" "^5.4.7"
"@0x/contracts-test-utils" "^5.4.8"
"@0x/typescript-typings" "^5.2.0"
"@0x/utils" "^6.4.3"
ethereum-types "^3.5.0"
ethereumjs-util "^7.0.10"
"@0x/contracts-test-utils@^5.4.7":
version "5.4.7"
resolved "https://registry.yarnpkg.com/@0x/contracts-test-utils/-/contracts-test-utils-5.4.7.tgz#2bd007ddcf95ec211642f1c656043b79046737df"
"@0x/contracts-zero-ex@^0.27.0":
version "0.27.1"
resolved "https://registry.yarnpkg.com/@0x/contracts-zero-ex/-/contracts-zero-ex-0.27.1.tgz#968fe9d8134972cb464f7c4a33c4e4089ba9218e"
dependencies:
"@0x/assert" "^3.0.27"
"@0x/base-contract" "^6.4.0"
"@0x/contract-addresses" "^6.6.0"
"@0x/dev-utils" "^4.2.7"
"@0x/json-schemas" "^6.1.3"
"@0x/order-utils" "^10.4.28"
"@0x/sol-coverage" "^4.0.37"
"@0x/sol-profiler" "^4.1.27"
"@0x/sol-trace" "^3.0.37"
"@0x/protocol-utils" "^1.8.1"
"@0x/subproviders" "^6.5.3"
"@0x/types" "^3.3.3"
"@0x/typescript-typings" "^5.2.0"
"@0x/utils" "^6.4.3"
"@0x/web3-wrapper" "^7.5.3"
"@types/bn.js" "^4.11.0"
"@types/js-combinatorics" "^0.5.29"
"@types/lodash" "4.14.104"
"@types/mocha" "^5.2.7"
"@types/node" "12.12.54"
bn.js "^4.11.8"
chai "^4.0.1"
chai-as-promised "^7.1.0"
chai-bignumber "^3.0.0"
decimal.js "^10.2.0"
dirty-chai "^2.0.1"
ethereum-types "^3.5.0"
ethereumjs-util "^7.0.10"
ethers "~4.0.4"
js-combinatorics "^0.5.3"
lodash "^4.17.11"
make-promises-safe "^1.1.0"
mocha "^6.2.0"
"@0x/contracts-utils@^4.7.15":
version "4.7.15"
resolved "https://registry.yarnpkg.com/@0x/contracts-utils/-/contracts-utils-4.7.15.tgz#f3f150b190b78c99f45caa34edcff98f6c002d1c"
dependencies:
"@0x/base-contract" "^6.4.0"
"@0x/typescript-typings" "^5.2.0"
"@0x/utils" "^6.4.3"
bn.js "^4.11.8"
ethereum-types "^3.5.0"
"@0x/dev-utils@^4.2.7":
version "4.2.7"
@ -1003,7 +929,7 @@
typedoc "~0.16.11"
yargs "^10.0.3"
"@0x/order-utils@^10.2.4", "@0x/order-utils@^10.4.27", "@0x/order-utils@^10.4.28":
"@0x/order-utils@^10.2.4", "@0x/order-utils@^10.4.28":
version "10.4.28"
resolved "https://registry.yarnpkg.com/@0x/order-utils/-/order-utils-10.4.28.tgz#c7b2f7d87a7f9834f9aa6186fbac68f32a05a81d"
dependencies: