@0x/contracts-erc20-bridge-sampler: Add UniswapV2.
				
					
				
			This commit is contained in:
		@@ -17,6 +17,10 @@
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Use `searchBestRate` in Kyber samples. Return 0 when Uniswap/Eth2Dai reserve",
 | 
			
		||||
                "pr": 2575
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add UniswapV2",
 | 
			
		||||
                "pr": 2595
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@ import "./IUniswapExchangeQuotes.sol";
 | 
			
		||||
import "./ICurve.sol";
 | 
			
		||||
import "./ILiquidityProvider.sol";
 | 
			
		||||
import "./ILiquidityProviderRegistry.sol";
 | 
			
		||||
import "./IUniswapV2Router.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ERC20BridgeSampler is
 | 
			
		||||
@@ -46,6 +47,8 @@ contract ERC20BridgeSampler is
 | 
			
		||||
    uint256 constant internal KYBER_CALL_GAS = 1500e3; // 1.5m
 | 
			
		||||
    /// @dev Gas limit for Uniswap calls.
 | 
			
		||||
    uint256 constant internal UNISWAP_CALL_GAS = 150e3; // 150k
 | 
			
		||||
    /// @dev Gas limit for UniswapV2 calls.
 | 
			
		||||
    uint256 constant internal UNISWAPV2_CALL_GAS = 150e3; // 150k
 | 
			
		||||
    /// @dev Base gas limit for Eth2Dai calls.
 | 
			
		||||
    uint256 constant internal ETH2DAI_CALL_GAS = 1000e3; // 1m
 | 
			
		||||
    /// @dev Base gas limit for Curve calls. Some Curves have multiple tokens
 | 
			
		||||
@@ -645,6 +648,74 @@ contract ERC20BridgeSampler is
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from UniswapV2.
 | 
			
		||||
    /// @param path Token route.
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromUniswapV2(
 | 
			
		||||
        address[] memory path,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            (bool didSucceed, bytes memory resultData) =
 | 
			
		||||
                _getUniswapV2RouterAddress().staticcall.gas(UNISWAPV2_CALL_GAS)(
 | 
			
		||||
                    abi.encodeWithSelector(
 | 
			
		||||
                        IUniswapV2Router(0).getAmountsOut.selector,
 | 
			
		||||
                        takerTokenAmounts[i],
 | 
			
		||||
                        path
 | 
			
		||||
                    ));
 | 
			
		||||
            uint256 buyAmount = 0;
 | 
			
		||||
            if (didSucceed) {
 | 
			
		||||
                // solhint-disable-next-line indent
 | 
			
		||||
                buyAmount = abi.decode(resultData, (uint256[]))[path.length - 1];
 | 
			
		||||
            } else {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            makerTokenAmounts[i] = buyAmount;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from UniswapV2.
 | 
			
		||||
    /// @param path Token route.
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromUniswapV2(
 | 
			
		||||
        address[] memory path,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            (bool didSucceed, bytes memory resultData) =
 | 
			
		||||
                _getUniswapV2RouterAddress().staticcall.gas(UNISWAPV2_CALL_GAS)(
 | 
			
		||||
                    abi.encodeWithSelector(
 | 
			
		||||
                        IUniswapV2Router(0).getAmountsIn.selector,
 | 
			
		||||
                        makerTokenAmounts[i],
 | 
			
		||||
                        path
 | 
			
		||||
                    ));
 | 
			
		||||
            uint256 sellAmount = 0;
 | 
			
		||||
            if (didSucceed) {
 | 
			
		||||
                // solhint-disable-next-line indent
 | 
			
		||||
                sellAmount = abi.decode(resultData, (uint256[]))[path.length - 1];
 | 
			
		||||
            } else {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            takerTokenAmounts[i] = sellAmount;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Overridable way to get token decimals.
 | 
			
		||||
    /// @param tokenAddress Address of the token.
 | 
			
		||||
    /// @return decimals The decimal places for the token.
 | 
			
		||||
 
 | 
			
		||||
@@ -240,4 +240,30 @@ interface IERC20BridgeSampler {
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address providerAddress);
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from UniswapV2.
 | 
			
		||||
    /// @param path Token route.
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromUniswapV2(
 | 
			
		||||
        address[] calldata path,
 | 
			
		||||
        uint256[] calldata takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts);
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from UniswapV2.
 | 
			
		||||
    /// @param path Token route.
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromUniswapV2(
 | 
			
		||||
        address[] calldata path,
 | 
			
		||||
        uint256[] calldata makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2019 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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IUniswapV2Router {
 | 
			
		||||
 | 
			
		||||
    function getAmountsOut(uint256 amountIn, address[] calldata path)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory amounts);
 | 
			
		||||
 | 
			
		||||
    function getAmountsIn(uint256 amountOut, address[] calldata path)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory amounts);
 | 
			
		||||
}
 | 
			
		||||
@@ -25,6 +25,7 @@ import "../src/ERC20BridgeSampler.sol";
 | 
			
		||||
import "../src/IEth2Dai.sol";
 | 
			
		||||
import "../src/IDevUtils.sol";
 | 
			
		||||
import "../src/IKyberNetworkProxy.sol";
 | 
			
		||||
import "../src/IUniswapV2Router.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
library LibDeterministicQuotes {
 | 
			
		||||
@@ -194,6 +195,55 @@ contract TestERC20BridgeSamplerUniswapExchange is
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestERC20BridgeSamplerUniswapV2Router is
 | 
			
		||||
    IUniswapV2Router,
 | 
			
		||||
    DeploymentConstants,
 | 
			
		||||
    FailTrigger
 | 
			
		||||
{
 | 
			
		||||
    bytes32 constant private SALT = 0xadc7fcb33c735913b8635927e66896b356a53a912ab2ceff929e60a04b53b3c1;
 | 
			
		||||
 | 
			
		||||
    // Deterministic `IUniswapV2Router.getAmountsOut()`.
 | 
			
		||||
    function getAmountsOut(uint256 amountIn, address[] calldata path)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory amounts)
 | 
			
		||||
    {
 | 
			
		||||
        require(path.length >= 2, "PATH_TOO_SHORT");
 | 
			
		||||
        _revertIfShouldFail();
 | 
			
		||||
        amounts = new uint256[](path.length);
 | 
			
		||||
        amounts[0] = amountIn;
 | 
			
		||||
        for (uint256 i = 0; i < path.length - 1; ++i) {
 | 
			
		||||
            amounts[i + 1] = LibDeterministicQuotes.getDeterministicSellQuote(
 | 
			
		||||
                SALT,
 | 
			
		||||
                path[i],
 | 
			
		||||
                path[i + 1],
 | 
			
		||||
                amounts[i]
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Deterministic `IUniswapV2Router.getAmountsInt()`.
 | 
			
		||||
    function getAmountsIn(uint256 amountOut, address[] calldata path)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory amounts)
 | 
			
		||||
    {
 | 
			
		||||
        require(path.length >= 2, "PATH_TOO_SHORT");
 | 
			
		||||
        _revertIfShouldFail();
 | 
			
		||||
        amounts = new uint256[](path.length);
 | 
			
		||||
        amounts[0] = amountOut;
 | 
			
		||||
        for (uint256 i = 0; i < path.length - 1; ++i) {
 | 
			
		||||
            amounts[i + 1] = LibDeterministicQuotes.getDeterministicBuyQuote(
 | 
			
		||||
                SALT,
 | 
			
		||||
                path[i],
 | 
			
		||||
                path[i + 1],
 | 
			
		||||
                amounts[i]
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestERC20BridgeSamplerKyberNetwork is
 | 
			
		||||
    IKyberNetwork,
 | 
			
		||||
    DeploymentConstants,
 | 
			
		||||
@@ -325,6 +375,7 @@ contract TestERC20BridgeSampler is
 | 
			
		||||
    FailTrigger
 | 
			
		||||
{
 | 
			
		||||
    TestERC20BridgeSamplerUniswapExchangeFactory public uniswap;
 | 
			
		||||
    TestERC20BridgeSamplerUniswapV2Router public uniswapV2Router;
 | 
			
		||||
    TestERC20BridgeSamplerEth2Dai public eth2Dai;
 | 
			
		||||
    TestERC20BridgeSamplerKyberNetwork public kyber;
 | 
			
		||||
 | 
			
		||||
@@ -332,6 +383,7 @@ contract TestERC20BridgeSampler is
 | 
			
		||||
 | 
			
		||||
    constructor() public ERC20BridgeSampler(address(this)) {
 | 
			
		||||
        uniswap = new TestERC20BridgeSamplerUniswapExchangeFactory();
 | 
			
		||||
        uniswapV2Router = new TestERC20BridgeSamplerUniswapV2Router();
 | 
			
		||||
        eth2Dai = new TestERC20BridgeSamplerEth2Dai();
 | 
			
		||||
        kyber = new TestERC20BridgeSamplerKyberNetwork();
 | 
			
		||||
    }
 | 
			
		||||
@@ -399,6 +451,15 @@ contract TestERC20BridgeSampler is
 | 
			
		||||
        return address(uniswap);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Overriden to point to a custom contract.
 | 
			
		||||
    function _getUniswapV2RouterAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address uniswapV2RouterAddress)
 | 
			
		||||
    {
 | 
			
		||||
        return address(uniswapV2Router);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Overriden to point to a custom contract.
 | 
			
		||||
    function _getKyberNetworkProxyAddress()
 | 
			
		||||
        internal
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@
 | 
			
		||||
    "config": {
 | 
			
		||||
        "publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
 | 
			
		||||
        "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
 | 
			
		||||
        "abis": "./test/generated-artifacts/@(DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IKyberNetworkProxy|ILiquidityProvider|ILiquidityProviderRegistry|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
 | 
			
		||||
        "abis": "./test/generated-artifacts/@(DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IKyberNetworkProxy|ILiquidityProvider|ILiquidityProviderRegistry|IUniswapExchangeQuotes|IUniswapV2Router|TestERC20BridgeSampler).json"
 | 
			
		||||
    },
 | 
			
		||||
    "repository": {
 | 
			
		||||
        "type": "git",
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkPr
 | 
			
		||||
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
 | 
			
		||||
import * as ILiquidityProviderRegistry from '../test/generated-artifacts/ILiquidityProviderRegistry.json';
 | 
			
		||||
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
 | 
			
		||||
import * as IUniswapV2Router from '../test/generated-artifacts/IUniswapV2Router.json';
 | 
			
		||||
import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json';
 | 
			
		||||
export const artifacts = {
 | 
			
		||||
    DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact,
 | 
			
		||||
@@ -31,5 +32,6 @@ export const artifacts = {
 | 
			
		||||
    ILiquidityProvider: ILiquidityProvider as ContractArtifact,
 | 
			
		||||
    ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
 | 
			
		||||
    IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
 | 
			
		||||
    IUniswapV2Router: IUniswapV2Router as ContractArtifact,
 | 
			
		||||
    TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ blockchainTests('erc20-bridge-sampler', env => {
 | 
			
		||||
    const KYBER_SALT = '0x0ff3ca9d46195c39f9a12afb74207b4970349fb3cfb1e459bbf170298d326bc7';
 | 
			
		||||
    const ETH2DAI_SALT = '0xb713b61bb9bb2958a0f5d1534b21e94fc68c4c0c034b0902ed844f2f6cd1b4f7';
 | 
			
		||||
    const UNISWAP_BASE_SALT = '0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab';
 | 
			
		||||
    const UNISWAP_V2_SALT = '0xadc7fcb33c735913b8635927e66896b356a53a912ab2ceff929e60a04b53b3c1';
 | 
			
		||||
    const ERC20_PROXY_ID = '0xf47261b0';
 | 
			
		||||
    const INVALID_TOKEN_PAIR_ERROR = 'ERC20BridgeSampler/INVALID_TOKEN_PAIR';
 | 
			
		||||
    const MAKER_TOKEN = randomAddress();
 | 
			
		||||
@@ -191,6 +192,22 @@ blockchainTests('erc20-bridge-sampler', env => {
 | 
			
		||||
        return quotes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getDeterministicUniswapV2SellQuote(path: string[], sellAmount: BigNumber): BigNumber {
 | 
			
		||||
        let bought = sellAmount;
 | 
			
		||||
        for (let i = 0; i < path.length - 1; ++i) {
 | 
			
		||||
            bought = getDeterministicSellQuote(UNISWAP_V2_SALT, path[i], path[i + 1], bought);
 | 
			
		||||
        }
 | 
			
		||||
        return bought;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getDeterministicUniswapV2BuyQuote(path: string[], buyAmount: BigNumber): BigNumber {
 | 
			
		||||
        let sold = buyAmount;
 | 
			
		||||
        for (let i = 0; i < path.length - 1; ++i) {
 | 
			
		||||
            sold = getDeterministicBuyQuote(UNISWAP_V2_SALT, path[i], path[i + 1], sold);
 | 
			
		||||
        }
 | 
			
		||||
        return sold;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
 | 
			
		||||
        const hash = getPackedHash(hexUtils.leftPad(order.salt));
 | 
			
		||||
        const orderStatus = new BigNumber(hash).mod(100).toNumber() > 90 ? 5 : 3;
 | 
			
		||||
@@ -926,6 +943,86 @@ blockchainTests('erc20-bridge-sampler', env => {
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    blockchainTests.resets('sampleSellsFromUniswapV2()', () => {
 | 
			
		||||
        function predictSellQuotes(path: string[], sellAmounts: BigNumber[]): BigNumber[] {
 | 
			
		||||
            return sellAmounts.map(a => getDeterministicUniswapV2SellQuote(path, a));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        it('can return no quotes', async () => {
 | 
			
		||||
            const quotes = await testContract.sampleSellsFromUniswapV2([TAKER_TOKEN, MAKER_TOKEN], []).callAsync();
 | 
			
		||||
            expect(quotes).to.deep.eq([]);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('can quote token -> token', async () => {
 | 
			
		||||
            const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
 | 
			
		||||
            const expectedQuotes = predictSellQuotes([TAKER_TOKEN, MAKER_TOKEN], sampleAmounts);
 | 
			
		||||
            const quotes = await testContract
 | 
			
		||||
                .sampleSellsFromUniswapV2([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
 | 
			
		||||
                .sampleSellsFromUniswapV2([TAKER_TOKEN, MAKER_TOKEN], sampleAmounts)
 | 
			
		||||
                .callAsync();
 | 
			
		||||
            expect(quotes).to.deep.eq(expectedQuotes);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('can quote token -> token -> token', async () => {
 | 
			
		||||
            const intermediateToken = randomAddress();
 | 
			
		||||
            const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
 | 
			
		||||
            const expectedQuotes = predictSellQuotes([TAKER_TOKEN, intermediateToken, MAKER_TOKEN], sampleAmounts);
 | 
			
		||||
            const quotes = await testContract
 | 
			
		||||
                .sampleSellsFromUniswapV2([TAKER_TOKEN, intermediateToken, MAKER_TOKEN], sampleAmounts)
 | 
			
		||||
                .callAsync();
 | 
			
		||||
            expect(quotes).to.deep.eq(expectedQuotes);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    blockchainTests.resets('sampleBuysFromUniswapV2()', () => {
 | 
			
		||||
        function predictBuyQuotes(path: string[], buyAmounts: BigNumber[]): BigNumber[] {
 | 
			
		||||
            return buyAmounts.map(a => getDeterministicUniswapV2BuyQuote(path, a));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        it('can return no quotes', async () => {
 | 
			
		||||
            const quotes = await testContract.sampleBuysFromUniswapV2([TAKER_TOKEN, MAKER_TOKEN], []).callAsync();
 | 
			
		||||
            expect(quotes).to.deep.eq([]);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('can quote token -> token', async () => {
 | 
			
		||||
            const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
 | 
			
		||||
            const expectedQuotes = predictBuyQuotes([TAKER_TOKEN, MAKER_TOKEN], sampleAmounts);
 | 
			
		||||
            const quotes = await testContract
 | 
			
		||||
                .sampleBuysFromUniswapV2([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
 | 
			
		||||
                .sampleBuysFromUniswapV2([TAKER_TOKEN, MAKER_TOKEN], sampleAmounts)
 | 
			
		||||
                .callAsync();
 | 
			
		||||
            expect(quotes).to.deep.eq(expectedQuotes);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('can quote token -> token -> token', async () => {
 | 
			
		||||
            const intermediateToken = randomAddress();
 | 
			
		||||
            const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
 | 
			
		||||
            const expectedQuotes = predictBuyQuotes([TAKER_TOKEN, intermediateToken, MAKER_TOKEN], sampleAmounts);
 | 
			
		||||
            const quotes = await testContract
 | 
			
		||||
                .sampleBuysFromUniswapV2([TAKER_TOKEN, intermediateToken, MAKER_TOKEN], sampleAmounts)
 | 
			
		||||
                .callAsync();
 | 
			
		||||
            expect(quotes).to.deep.eq(expectedQuotes);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('batchCall()', () => {
 | 
			
		||||
        it('can call one function', async () => {
 | 
			
		||||
            const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
 | 
			
		||||
 
 | 
			
		||||
@@ -15,4 +15,5 @@ export * from '../test/generated-wrappers/i_kyber_network_proxy';
 | 
			
		||||
export * from '../test/generated-wrappers/i_liquidity_provider';
 | 
			
		||||
export * from '../test/generated-wrappers/i_liquidity_provider_registry';
 | 
			
		||||
export * from '../test/generated-wrappers/i_uniswap_exchange_quotes';
 | 
			
		||||
export * from '../test/generated-wrappers/i_uniswap_v2_router';
 | 
			
		||||
export * from '../test/generated-wrappers/test_erc20_bridge_sampler';
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@
 | 
			
		||||
        "test/generated-artifacts/ILiquidityProvider.json",
 | 
			
		||||
        "test/generated-artifacts/ILiquidityProviderRegistry.json",
 | 
			
		||||
        "test/generated-artifacts/IUniswapExchangeQuotes.json",
 | 
			
		||||
        "test/generated-artifacts/IUniswapV2Router.json",
 | 
			
		||||
        "test/generated-artifacts/TestERC20BridgeSampler.json"
 | 
			
		||||
    ],
 | 
			
		||||
    "exclude": ["./deploy/solc/solc_bin"]
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add UniswapV2 addresses to `DeploymentConstants`",
 | 
			
		||||
                "pr": "TODO"
 | 
			
		||||
                "pr": 2595
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user