Merge branch 'development' of github.com:0xProject/0x-monorepo into refactor_rfq_comparison_price_integration
# Conflicts: # packages/asset-swapper/src/utils/market_operation_utils/index.ts
This commit is contained in:
		@@ -26,6 +26,10 @@
 | 
			
		||||
                "note": "Reworked `KyberBridge`",
 | 
			
		||||
                "pr": 2683
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added `CreamBridge`",
 | 
			
		||||
                "pr": 2715
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added `ShellBridge`",
 | 
			
		||||
                "pr": 2722
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										103
									
								
								contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/IBalancerPool.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract CreamBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
 | 
			
		||||
    ///      token encoded in the bridge data, then transfers the bought
 | 
			
		||||
    ///      tokens to `to`.
 | 
			
		||||
    /// @param toTokenAddress The token to buy and transfer to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // Decode the bridge data.
 | 
			
		||||
        (address fromTokenAddress, address poolAddress) = abi.decode(
 | 
			
		||||
            bridgeData,
 | 
			
		||||
            (address, address)
 | 
			
		||||
        );
 | 
			
		||||
        require(toTokenAddress != fromTokenAddress, "CreamBridge/INVALID_PAIR");
 | 
			
		||||
 | 
			
		||||
        uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Grant an allowance to the exchange to spend `fromTokenAddress` token.
 | 
			
		||||
        LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance);
 | 
			
		||||
 | 
			
		||||
        // Sell all of this contract's `fromTokenAddress` token balance.
 | 
			
		||||
        (uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn(
 | 
			
		||||
            fromTokenAddress, // tokenIn
 | 
			
		||||
            fromTokenBalance, // tokenAmountIn
 | 
			
		||||
            toTokenAddress,   // tokenOut
 | 
			
		||||
            amount,           // minAmountOut
 | 
			
		||||
            uint256(-1)       // maxPrice
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Transfer the converted `toToken`s to `to`.
 | 
			
		||||
        LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            boughtAmount,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -38,7 +38,7 @@
 | 
			
		||||
        "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
 | 
			
		||||
    },
 | 
			
		||||
    "config": {
 | 
			
		||||
        "abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|StaticCallProxy|SushiSwapBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
 | 
			
		||||
        "abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CreamBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|StaticCallProxy|SushiSwapBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
 | 
			
		||||
        "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
 | 
			
		||||
    },
 | 
			
		||||
    "repository": {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import { ContractArtifact } from 'ethereum-types';
 | 
			
		||||
import * as BalancerBridge from '../generated-artifacts/BalancerBridge.json';
 | 
			
		||||
import * as BancorBridge from '../generated-artifacts/BancorBridge.json';
 | 
			
		||||
import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json';
 | 
			
		||||
import * as CreamBridge from '../generated-artifacts/CreamBridge.json';
 | 
			
		||||
import * as CurveBridge from '../generated-artifacts/CurveBridge.json';
 | 
			
		||||
import * as DexForwarderBridge from '../generated-artifacts/DexForwarderBridge.json';
 | 
			
		||||
import * as DODOBridge from '../generated-artifacts/DODOBridge.json';
 | 
			
		||||
@@ -73,6 +74,7 @@ export const artifacts = {
 | 
			
		||||
    BalancerBridge: BalancerBridge as ContractArtifact,
 | 
			
		||||
    BancorBridge: BancorBridge as ContractArtifact,
 | 
			
		||||
    ChaiBridge: ChaiBridge as ContractArtifact,
 | 
			
		||||
    CreamBridge: CreamBridge as ContractArtifact,
 | 
			
		||||
    CurveBridge: CurveBridge as ContractArtifact,
 | 
			
		||||
    DODOBridge: DODOBridge as ContractArtifact,
 | 
			
		||||
    DexForwarderBridge: DexForwarderBridge as ContractArtifact,
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
export * from '../generated-wrappers/balancer_bridge';
 | 
			
		||||
export * from '../generated-wrappers/bancor_bridge';
 | 
			
		||||
export * from '../generated-wrappers/chai_bridge';
 | 
			
		||||
export * from '../generated-wrappers/cream_bridge';
 | 
			
		||||
export * from '../generated-wrappers/curve_bridge';
 | 
			
		||||
export * from '../generated-wrappers/d_o_d_o_bridge';
 | 
			
		||||
export * from '../generated-wrappers/dex_forwarder_bridge';
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import { ContractArtifact } from 'ethereum-types';
 | 
			
		||||
import * as BalancerBridge from '../test/generated-artifacts/BalancerBridge.json';
 | 
			
		||||
import * as BancorBridge from '../test/generated-artifacts/BancorBridge.json';
 | 
			
		||||
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
 | 
			
		||||
import * as CreamBridge from '../test/generated-artifacts/CreamBridge.json';
 | 
			
		||||
import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json';
 | 
			
		||||
import * as DexForwarderBridge from '../test/generated-artifacts/DexForwarderBridge.json';
 | 
			
		||||
import * as DODOBridge from '../test/generated-artifacts/DODOBridge.json';
 | 
			
		||||
@@ -73,6 +74,7 @@ export const artifacts = {
 | 
			
		||||
    BalancerBridge: BalancerBridge as ContractArtifact,
 | 
			
		||||
    BancorBridge: BancorBridge as ContractArtifact,
 | 
			
		||||
    ChaiBridge: ChaiBridge as ContractArtifact,
 | 
			
		||||
    CreamBridge: CreamBridge as ContractArtifact,
 | 
			
		||||
    CurveBridge: CurveBridge as ContractArtifact,
 | 
			
		||||
    DODOBridge: DODOBridge as ContractArtifact,
 | 
			
		||||
    DexForwarderBridge: DexForwarderBridge as ContractArtifact,
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
export * from '../test/generated-wrappers/balancer_bridge';
 | 
			
		||||
export * from '../test/generated-wrappers/bancor_bridge';
 | 
			
		||||
export * from '../test/generated-wrappers/chai_bridge';
 | 
			
		||||
export * from '../test/generated-wrappers/cream_bridge';
 | 
			
		||||
export * from '../test/generated-wrappers/curve_bridge';
 | 
			
		||||
export * from '../test/generated-wrappers/d_o_d_o_bridge';
 | 
			
		||||
export * from '../test/generated-wrappers/dex_forwarder_bridge';
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
        "generated-artifacts/BalancerBridge.json",
 | 
			
		||||
        "generated-artifacts/BancorBridge.json",
 | 
			
		||||
        "generated-artifacts/ChaiBridge.json",
 | 
			
		||||
        "generated-artifacts/CreamBridge.json",
 | 
			
		||||
        "generated-artifacts/CurveBridge.json",
 | 
			
		||||
        "generated-artifacts/DODOBridge.json",
 | 
			
		||||
        "generated-artifacts/DexForwarderBridge.json",
 | 
			
		||||
@@ -61,6 +62,7 @@
 | 
			
		||||
        "test/generated-artifacts/BalancerBridge.json",
 | 
			
		||||
        "test/generated-artifacts/BancorBridge.json",
 | 
			
		||||
        "test/generated-artifacts/ChaiBridge.json",
 | 
			
		||||
        "test/generated-artifacts/CreamBridge.json",
 | 
			
		||||
        "test/generated-artifacts/CurveBridge.json",
 | 
			
		||||
        "test/generated-artifacts/DODOBridge.json",
 | 
			
		||||
        "test/generated-artifacts/DexForwarderBridge.json",
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,10 @@
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added `Shell` into FQT",
 | 
			
		||||
                "pr": 2722
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added `CREAM` into FQT",
 | 
			
		||||
                "pr": 2715
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,7 @@ contract BridgeAdapter is
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    address private immutable BALANCER_BRIDGE_ADDRESS;
 | 
			
		||||
    address private immutable CREAM_BRIDGE_ADDRESS;
 | 
			
		||||
    address private immutable CURVE_BRIDGE_ADDRESS;
 | 
			
		||||
    address private immutable KYBER_BRIDGE_ADDRESS;
 | 
			
		||||
    address private immutable MOONISWAP_BRIDGE_ADDRESS;
 | 
			
		||||
@@ -93,6 +94,7 @@ contract BridgeAdapter is
 | 
			
		||||
        SHELL_BRIDGE_ADDRESS = addresses.shellBridge;
 | 
			
		||||
        UNISWAP_BRIDGE_ADDRESS = addresses.uniswapBridge;
 | 
			
		||||
        UNISWAP_V2_BRIDGE_ADDRESS = addresses.uniswapV2Bridge;
 | 
			
		||||
        CREAM_BRIDGE_ADDRESS = addresses.creamBridge;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function trade(
 | 
			
		||||
@@ -134,7 +136,7 @@ contract BridgeAdapter is
 | 
			
		||||
                sellAmount,
 | 
			
		||||
                bridgeData
 | 
			
		||||
            );
 | 
			
		||||
        } else if (bridgeAddress == BALANCER_BRIDGE_ADDRESS) {
 | 
			
		||||
        } else if (bridgeAddress == BALANCER_BRIDGE_ADDRESS  || bridgeAddress == CREAM_BRIDGE_ADDRESS) {
 | 
			
		||||
            boughtAmount = _tradeBalancer(
 | 
			
		||||
                buyToken,
 | 
			
		||||
                sellAmount,
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ contract MixinAdapterAddresses
 | 
			
		||||
    struct AdapterAddresses {
 | 
			
		||||
        // Bridges
 | 
			
		||||
        address balancerBridge;
 | 
			
		||||
        address creamBridge;
 | 
			
		||||
        address curveBridge;
 | 
			
		||||
        address kyberBridge;
 | 
			
		||||
        address mooniswapBridge;
 | 
			
		||||
 
 | 
			
		||||
@@ -75,6 +75,7 @@ blockchainTests.resets('FillQuoteTransformer', env => {
 | 
			
		||||
                weth: NULL_ADDRESS,
 | 
			
		||||
                shellBridge: NULL_ADDRESS,
 | 
			
		||||
                shell: NULL_ADDRESS,
 | 
			
		||||
                creamBridge: NULL_ADDRESS,
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        transformer = await FillQuoteTransformerContract.deployFrom0xArtifactAsync(
 | 
			
		||||
 
 | 
			
		||||
@@ -153,6 +153,18 @@
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added `DODO`",
 | 
			
		||||
                "pr": 2701
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Fix for some edge cases with `includedSources` and `MultiHop`",
 | 
			
		||||
                "pr": 2730
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Introduced `excludedFeeSources` to disable sources when determining the price of an asset in ETH",
 | 
			
		||||
                "pr": 2731
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Support DODO Trade Allowed parameter to automatically disable the pool",
 | 
			
		||||
                "pr": 2732
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@ interface IDODOHelper {
 | 
			
		||||
 | 
			
		||||
interface IDODO {
 | 
			
		||||
    function querySellBaseToken(uint256 amount) external view returns (uint256);
 | 
			
		||||
    function _TRADE_ALLOWED_() external view returns (bool);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract DODOSampler is
 | 
			
		||||
@@ -80,6 +81,11 @@ contract DODOSampler is
 | 
			
		||||
            sellBase = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // DODO Pool has been disabled
 | 
			
		||||
        if (!IDODO(pool)._TRADE_ALLOWED_()) {
 | 
			
		||||
            return (sellBase, pool, makerTokenAmounts);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            uint256 buyAmount = _sampleSellForApproximateBuyFromDODO(
 | 
			
		||||
                abi.encode(takerToken, pool, baseToken), // taker token data
 | 
			
		||||
@@ -132,6 +138,11 @@ contract DODOSampler is
 | 
			
		||||
            sellBase = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // DODO Pool has been disabled
 | 
			
		||||
        if (!IDODO(pool)._TRADE_ALLOWED_()) {
 | 
			
		||||
            return (sellBase, pool, takerTokenAmounts);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        takerTokenAmounts = _sampleApproximateBuys(
 | 
			
		||||
            ApproximateBuyQuoteOpts({
 | 
			
		||||
                makerTokenData: abi.encode(makerToken, pool, baseToken),
 | 
			
		||||
 
 | 
			
		||||
@@ -71,8 +71,13 @@
 | 
			
		||||
        "@0x/web3-wrapper": "^7.2.0",
 | 
			
		||||
        "@balancer-labs/sor": "0.3.2",
 | 
			
		||||
        "@bancor/sdk": "^0.2.9",
 | 
			
		||||
        "@ethersproject/abi": "^5.0.1",
 | 
			
		||||
        "@ethersproject/address": "^5.0.1",
 | 
			
		||||
        "@ethersproject/contracts": "^5.0.1",
 | 
			
		||||
        "@ethersproject/providers": "^5.0.4",
 | 
			
		||||
        "axios": "^0.19.2",
 | 
			
		||||
        "axios-mock-adapter": "^1.18.1",
 | 
			
		||||
        "cream-sor": "^0.3.3",
 | 
			
		||||
        "decimal.js": "^10.2.0",
 | 
			
		||||
        "ethereum-types": "^3.2.0",
 | 
			
		||||
        "ethereumjs-util": "^5.1.1",
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ export const SELL_SOURCE_FILTER = new SourceFilters([
 | 
			
		||||
    ERC20BridgeSource.Shell,
 | 
			
		||||
    ERC20BridgeSource.MultiHop,
 | 
			
		||||
    ERC20BridgeSource.Dodo,
 | 
			
		||||
    ERC20BridgeSource.Cream,
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -47,6 +48,7 @@ export const BUY_SOURCE_FILTER = new SourceFilters(
 | 
			
		||||
        ERC20BridgeSource.SushiSwap,
 | 
			
		||||
        ERC20BridgeSource.MultiHop,
 | 
			
		||||
        ERC20BridgeSource.Dodo,
 | 
			
		||||
        ERC20BridgeSource.Cream,
 | 
			
		||||
    ],
 | 
			
		||||
    [ERC20BridgeSource.MultiBridge],
 | 
			
		||||
);
 | 
			
		||||
@@ -55,6 +57,7 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {
 | 
			
		||||
    // tslint:disable-next-line: custom-no-magic-numbers
 | 
			
		||||
    runLimit: 2 ** 15,
 | 
			
		||||
    excludedSources: [],
 | 
			
		||||
    excludedFeeSources: [],
 | 
			
		||||
    includedSources: [],
 | 
			
		||||
    bridgeSlippage: 0.005,
 | 
			
		||||
    maxFallbackSlippage: 0.05,
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,104 @@
 | 
			
		||||
import { getPoolsWithTokens, parsePoolData } from 'cream-sor';
 | 
			
		||||
 | 
			
		||||
import { BalancerPool } from './balancer_utils';
 | 
			
		||||
 | 
			
		||||
// tslint:disable:boolean-naming
 | 
			
		||||
 | 
			
		||||
interface CacheValue {
 | 
			
		||||
    timestamp: number;
 | 
			
		||||
    pools: BalancerPool[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tslint:disable:custom-no-magic-numbers
 | 
			
		||||
const FIVE_SECONDS_MS = 5 * 1000;
 | 
			
		||||
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
 | 
			
		||||
const DEFAULT_TIMEOUT_MS = 1000;
 | 
			
		||||
const MAX_POOLS_FETCHED = 3;
 | 
			
		||||
// tslint:enable:custom-no-magic-numbers
 | 
			
		||||
 | 
			
		||||
export class CreamPoolsCache {
 | 
			
		||||
    constructor(
 | 
			
		||||
        private readonly _cache: { [key: string]: CacheValue } = {},
 | 
			
		||||
        private readonly maxPoolsFetched: number = MAX_POOLS_FETCHED,
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    public async getPoolsForPairAsync(
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        timeoutMs: number = DEFAULT_TIMEOUT_MS,
 | 
			
		||||
    ): Promise<BalancerPool[]> {
 | 
			
		||||
        const timeout = new Promise<BalancerPool[]>(resolve => setTimeout(resolve, timeoutMs, []));
 | 
			
		||||
        return Promise.race([this._getPoolsForPairAsync(takerToken, makerToken), timeout]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public getCachedPoolAddressesForPair(
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        cacheExpiryMs?: number,
 | 
			
		||||
    ): string[] | undefined {
 | 
			
		||||
        const key = JSON.stringify([takerToken, makerToken]);
 | 
			
		||||
        const value = this._cache[key];
 | 
			
		||||
        if (cacheExpiryMs === undefined) {
 | 
			
		||||
            return value === undefined ? [] : value.pools.map(pool => pool.id);
 | 
			
		||||
        }
 | 
			
		||||
        const minTimestamp = Date.now() - cacheExpiryMs;
 | 
			
		||||
        if (value === undefined || value.timestamp < minTimestamp) {
 | 
			
		||||
            return undefined;
 | 
			
		||||
        } else {
 | 
			
		||||
            return value.pools.map(pool => pool.id);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public howToSampleCream(
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        isAllowedSource: boolean,
 | 
			
		||||
    ): { onChain: boolean; offChain: boolean } {
 | 
			
		||||
        // If CREAM is excluded as a source, do not sample.
 | 
			
		||||
        if (!isAllowedSource) {
 | 
			
		||||
            return { onChain: false, offChain: false };
 | 
			
		||||
        }
 | 
			
		||||
        const cachedCreamPools = this.getCachedPoolAddressesForPair(takerToken, makerToken, ONE_DAY_MS);
 | 
			
		||||
        // Sample CREAM on-chain (i.e. via the ERC20BridgeSampler contract) if:
 | 
			
		||||
        // - Cached values are not stale
 | 
			
		||||
        // - There is at least one CREAM pool for this pair
 | 
			
		||||
        const onChain = cachedCreamPools !== undefined && cachedCreamPools.length > 0;
 | 
			
		||||
        // Sample CREAM off-chain (i.e. via GraphQL query + `computeCreamBuy/SellQuote`)
 | 
			
		||||
        // if cached values are stale
 | 
			
		||||
        const offChain = cachedCreamPools === undefined;
 | 
			
		||||
        return { onChain, offChain };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected async _getPoolsForPairAsync(
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        cacheExpiryMs: number = FIVE_SECONDS_MS,
 | 
			
		||||
    ): Promise<BalancerPool[]> {
 | 
			
		||||
        const key = JSON.stringify([takerToken, makerToken]);
 | 
			
		||||
        const value = this._cache[key];
 | 
			
		||||
        const minTimestamp = Date.now() - cacheExpiryMs;
 | 
			
		||||
        if (value === undefined || value.timestamp < minTimestamp) {
 | 
			
		||||
            const pools = await this._fetchPoolsForPairAsync(takerToken, makerToken);
 | 
			
		||||
            const timestamp = Date.now();
 | 
			
		||||
            this._cache[key] = {
 | 
			
		||||
                pools,
 | 
			
		||||
                timestamp,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        return this._cache[key].pools;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // tslint:disable-next-line:prefer-function-over-method
 | 
			
		||||
    protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<BalancerPool[]> {
 | 
			
		||||
        try {
 | 
			
		||||
            const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools;
 | 
			
		||||
            // Sort by maker token balance (descending)
 | 
			
		||||
            const pools = parsePoolData(poolData, takerToken, makerToken).sort((a, b) =>
 | 
			
		||||
                b.balanceOut.minus(a.balanceOut).toNumber(),
 | 
			
		||||
            );
 | 
			
		||||
            return pools.length > this.maxPoolsFetched ? pools.slice(0, this.maxPoolsFetched) : pools;
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -141,10 +141,12 @@ export class MarketOperationUtils {
 | 
			
		||||
        const _opts = { ...DEFAULT_GET_MARKET_ORDERS_OPTS, ...opts };
 | 
			
		||||
        const [makerToken, takerToken] = getNativeOrderTokens(nativeOrders[0]);
 | 
			
		||||
        const sampleAmounts = getSampleAmounts(takerAmount, _opts.numSamples, _opts.sampleDistributionBase);
 | 
			
		||||
 | 
			
		||||
        const requestFilters = new SourceFilters().exclude(_opts.excludedSources).include(_opts.includedSources);
 | 
			
		||||
        const feeSourceFilters = this._feeSources.merge(requestFilters);
 | 
			
		||||
        const quoteSourceFilters = this._sellSources.merge(requestFilters);
 | 
			
		||||
 | 
			
		||||
        const feeSourceFilters = this._feeSources.exclude(_opts.excludedFeeSources);
 | 
			
		||||
 | 
			
		||||
        const {
 | 
			
		||||
            onChain: sampleBalancerOnChain,
 | 
			
		||||
            offChain: sampleBalancerOffChain,
 | 
			
		||||
@@ -154,6 +156,20 @@ export class MarketOperationUtils {
 | 
			
		||||
            quoteSourceFilters.isAllowed(ERC20BridgeSource.Balancer),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const {
 | 
			
		||||
            onChain: sampleCreamOnChain,
 | 
			
		||||
            offChain: sampleCreamOffChain,
 | 
			
		||||
        } = this._sampler.creamPoolsCache.howToSampleCream(
 | 
			
		||||
            takerToken,
 | 
			
		||||
            makerToken,
 | 
			
		||||
            quoteSourceFilters.isAllowed(ERC20BridgeSource.Cream),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const offChainSources = [
 | 
			
		||||
            ...(!sampleCreamOnChain ? [ERC20BridgeSource.Cream] : []),
 | 
			
		||||
            ...(!sampleBalancerOnChain ? [ERC20BridgeSource.Balancer] : []),
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        // Call the sampler contract.
 | 
			
		||||
        const samplerPromise = this._sampler.executeAsync(
 | 
			
		||||
            this._sampler.getTokenDecimals(makerToken, takerToken),
 | 
			
		||||
@@ -181,7 +197,7 @@ export class MarketOperationUtils {
 | 
			
		||||
            ),
 | 
			
		||||
            // Get sell quotes for taker -> maker.
 | 
			
		||||
            this._sampler.getSellQuotes(
 | 
			
		||||
                quoteSourceFilters.exclude(sampleBalancerOnChain ? [] : ERC20BridgeSource.Balancer).sources,
 | 
			
		||||
                quoteSourceFilters.exclude(offChainSources).sources,
 | 
			
		||||
                makerToken,
 | 
			
		||||
                takerToken,
 | 
			
		||||
                sampleAmounts,
 | 
			
		||||
@@ -204,6 +220,10 @@ export class MarketOperationUtils {
 | 
			
		||||
            ? this._sampler.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, sampleAmounts)
 | 
			
		||||
            : Promise.resolve([]);
 | 
			
		||||
 | 
			
		||||
        const offChainCreamPromise = sampleCreamOffChain
 | 
			
		||||
            ? this._sampler.getCreamSellQuotesOffChainAsync(makerToken, takerToken, sampleAmounts)
 | 
			
		||||
            : Promise.resolve([]);
 | 
			
		||||
 | 
			
		||||
        const offChainBancorPromise = quoteSourceFilters.isAllowed(ERC20BridgeSource.Bancor)
 | 
			
		||||
            ? this._sampler.getBancorSellQuotesOffChainAsync(makerToken, takerToken, [takerAmount])
 | 
			
		||||
            : Promise.resolve([]);
 | 
			
		||||
@@ -211,8 +231,14 @@ export class MarketOperationUtils {
 | 
			
		||||
        const [
 | 
			
		||||
            [tokenDecimals, orderFillableAmounts, ethToMakerAssetRate, ethToTakerAssetRate, dexQuotes, twoHopQuotes],
 | 
			
		||||
            offChainBalancerQuotes,
 | 
			
		||||
            offChainCreamQuotes,
 | 
			
		||||
            offChainBancorQuotes,
 | 
			
		||||
        ] = await Promise.all([samplerPromise, offChainBalancerPromise, offChainBancorPromise]);
 | 
			
		||||
        ] = await Promise.all([
 | 
			
		||||
            samplerPromise,
 | 
			
		||||
            offChainBalancerPromise,
 | 
			
		||||
            offChainCreamPromise,
 | 
			
		||||
            offChainBancorPromise,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        const [makerTokenDecimals, takerTokenDecimals] = tokenDecimals;
 | 
			
		||||
        return {
 | 
			
		||||
@@ -220,7 +246,7 @@ export class MarketOperationUtils {
 | 
			
		||||
            inputAmount: takerAmount,
 | 
			
		||||
            inputToken: takerToken,
 | 
			
		||||
            outputToken: makerToken,
 | 
			
		||||
            dexQuotes: dexQuotes.concat([...offChainBalancerQuotes, offChainBancorQuotes]),
 | 
			
		||||
            dexQuotes: dexQuotes.concat([...offChainBalancerQuotes, ...offChainCreamQuotes, offChainBancorQuotes]),
 | 
			
		||||
            nativeOrders,
 | 
			
		||||
            orderFillableAmounts,
 | 
			
		||||
            ethToOutputRate: ethToMakerAssetRate,
 | 
			
		||||
@@ -251,10 +277,12 @@ export class MarketOperationUtils {
 | 
			
		||||
        const _opts = { ...DEFAULT_GET_MARKET_ORDERS_OPTS, ...opts };
 | 
			
		||||
        const [makerToken, takerToken] = getNativeOrderTokens(nativeOrders[0]);
 | 
			
		||||
        const sampleAmounts = getSampleAmounts(makerAmount, _opts.numSamples, _opts.sampleDistributionBase);
 | 
			
		||||
 | 
			
		||||
        const requestFilters = new SourceFilters().exclude(_opts.excludedSources).include(_opts.includedSources);
 | 
			
		||||
        const feeSourceFilters = this._feeSources.merge(requestFilters);
 | 
			
		||||
        const quoteSourceFilters = this._buySources.merge(requestFilters);
 | 
			
		||||
 | 
			
		||||
        const feeSourceFilters = this._feeSources.exclude(_opts.excludedFeeSources);
 | 
			
		||||
 | 
			
		||||
        const {
 | 
			
		||||
            onChain: sampleBalancerOnChain,
 | 
			
		||||
            offChain: sampleBalancerOffChain,
 | 
			
		||||
@@ -264,6 +292,20 @@ export class MarketOperationUtils {
 | 
			
		||||
            quoteSourceFilters.isAllowed(ERC20BridgeSource.Balancer),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const {
 | 
			
		||||
            onChain: sampleCreamOnChain,
 | 
			
		||||
            offChain: sampleCreamOffChain,
 | 
			
		||||
        } = this._sampler.creamPoolsCache.howToSampleCream(
 | 
			
		||||
            takerToken,
 | 
			
		||||
            makerToken,
 | 
			
		||||
            quoteSourceFilters.isAllowed(ERC20BridgeSource.Cream),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const offChainSources = [
 | 
			
		||||
            ...(!sampleCreamOnChain ? [ERC20BridgeSource.Cream] : []),
 | 
			
		||||
            ...(!sampleBalancerOnChain ? [ERC20BridgeSource.Balancer] : []),
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        // Call the sampler contract.
 | 
			
		||||
        const samplerPromise = this._sampler.executeAsync(
 | 
			
		||||
            this._sampler.getTokenDecimals(makerToken, takerToken),
 | 
			
		||||
@@ -291,7 +333,7 @@ export class MarketOperationUtils {
 | 
			
		||||
            ),
 | 
			
		||||
            // Get buy quotes for taker -> maker.
 | 
			
		||||
            this._sampler.getBuyQuotes(
 | 
			
		||||
                quoteSourceFilters.exclude(sampleBalancerOnChain ? [] : ERC20BridgeSource.Balancer).sources,
 | 
			
		||||
                quoteSourceFilters.exclude(offChainSources).sources,
 | 
			
		||||
                makerToken,
 | 
			
		||||
                takerToken,
 | 
			
		||||
                sampleAmounts,
 | 
			
		||||
@@ -313,10 +355,15 @@ export class MarketOperationUtils {
 | 
			
		||||
            ? this._sampler.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, sampleAmounts)
 | 
			
		||||
            : Promise.resolve([]);
 | 
			
		||||
 | 
			
		||||
        const offChainCreamPromise = sampleCreamOffChain
 | 
			
		||||
            ? this._sampler.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, sampleAmounts)
 | 
			
		||||
            : Promise.resolve([]);
 | 
			
		||||
 | 
			
		||||
        const [
 | 
			
		||||
            [tokenDecimals, orderFillableAmounts, ethToMakerAssetRate, ethToTakerAssetRate, dexQuotes, twoHopQuotes],
 | 
			
		||||
            offChainBalancerQuotes,
 | 
			
		||||
        ] = await Promise.all([samplerPromise, offChainBalancerPromise]);
 | 
			
		||||
            offChainCreamQuotes,
 | 
			
		||||
        ] = await Promise.all([samplerPromise, offChainBalancerPromise, offChainCreamPromise]);
 | 
			
		||||
        // Attach the MultiBridge address to the sample fillData
 | 
			
		||||
        (dexQuotes.find(quotes => quotes[0] && quotes[0].source === ERC20BridgeSource.MultiBridge) || []).forEach(
 | 
			
		||||
            q => (q.fillData = { poolAddress: this._multiBridge }),
 | 
			
		||||
@@ -327,7 +374,7 @@ export class MarketOperationUtils {
 | 
			
		||||
            inputAmount: makerAmount,
 | 
			
		||||
            inputToken: makerToken,
 | 
			
		||||
            outputToken: takerToken,
 | 
			
		||||
            dexQuotes: dexQuotes.concat(offChainBalancerQuotes),
 | 
			
		||||
            dexQuotes: dexQuotes.concat(offChainBalancerQuotes, offChainCreamQuotes),
 | 
			
		||||
            nativeOrders,
 | 
			
		||||
            orderFillableAmounts,
 | 
			
		||||
            ethToOutputRate: ethToTakerAssetRate,
 | 
			
		||||
@@ -394,9 +441,10 @@ export class MarketOperationUtils {
 | 
			
		||||
        const _opts = { ...DEFAULT_GET_MARKET_ORDERS_OPTS, ...opts };
 | 
			
		||||
 | 
			
		||||
        const requestFilters = new SourceFilters().exclude(_opts.excludedSources).include(_opts.includedSources);
 | 
			
		||||
        const feeSourceFilters = this._feeSources.merge(requestFilters);
 | 
			
		||||
        const quoteSourceFilters = this._buySources.merge(requestFilters);
 | 
			
		||||
 | 
			
		||||
        const feeSourceFilters = this._feeSources.exclude(_opts.excludedFeeSources);
 | 
			
		||||
 | 
			
		||||
        const ops = [
 | 
			
		||||
            ...batchNativeOrders.map(orders =>
 | 
			
		||||
                this._sampler.getOrderFillableMakerAmounts(orders, this.contractAddresses.exchange),
 | 
			
		||||
@@ -520,11 +568,9 @@ export class MarketOperationUtils {
 | 
			
		||||
            ethToInputRate,
 | 
			
		||||
            exchangeProxyOverhead: opts.exchangeProxyOverhead || (() => ZERO_AMOUNT),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const optimalPath = await findOptimalPathAsync(side, fills, inputAmount, opts.runLimit, optimizerOpts);
 | 
			
		||||
        if (optimalPath === undefined) {
 | 
			
		||||
            throw new Error(AggregationError.NoOptimalPath);
 | 
			
		||||
        }
 | 
			
		||||
        const optimalPathRate = optimalPath.adjustedRate();
 | 
			
		||||
        const optimalPathRate = optimalPath ? optimalPath.adjustedRate() : ZERO_AMOUNT;
 | 
			
		||||
 | 
			
		||||
        const { adjustedRate: bestTwoHopRate, quote: bestTwoHopQuote } = getBestTwoHopQuote(
 | 
			
		||||
            marketSideLiquidity,
 | 
			
		||||
@@ -540,6 +586,11 @@ export class MarketOperationUtils {
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If there is no optimal path AND we didn't return a MultiHop quote, then throw
 | 
			
		||||
        if (optimalPath === undefined) {
 | 
			
		||||
            throw new Error(AggregationError.NoOptimalPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Generate a fallback path if native orders are in the optimal path.
 | 
			
		||||
        const nativeFills = optimalPath.fills.filter(f => f.source === ERC20BridgeSource.Native);
 | 
			
		||||
        if (opts.allowFallback && nativeFills.length !== 0) {
 | 
			
		||||
 
 | 
			
		||||
@@ -48,26 +48,37 @@ export function getBestTwoHopQuote(
 | 
			
		||||
    exchangeProxyOverhead?: ExchangeProxyOverhead,
 | 
			
		||||
): { quote: DexSample<MultiHopFillData> | undefined; adjustedRate: BigNumber } {
 | 
			
		||||
    const { side, inputAmount, ethToOutputRate, twoHopQuotes } = marketSideLiquidity;
 | 
			
		||||
    if (twoHopQuotes.length === 0) {
 | 
			
		||||
        return { adjustedRate: ZERO_AMOUNT, quote: undefined };
 | 
			
		||||
    // Ensure the expected data we require exists. In the case where all hops reverted
 | 
			
		||||
    // or there were no sources included that allowed for multi hop,
 | 
			
		||||
    // we can end up with empty, but not undefined, fill data
 | 
			
		||||
    const filteredQuotes = twoHopQuotes.filter(
 | 
			
		||||
        quote =>
 | 
			
		||||
            quote &&
 | 
			
		||||
            quote.fillData &&
 | 
			
		||||
            quote.fillData.firstHopSource &&
 | 
			
		||||
            quote.fillData.secondHopSource &&
 | 
			
		||||
            quote.output.isGreaterThan(ZERO_AMOUNT),
 | 
			
		||||
    );
 | 
			
		||||
    if (filteredQuotes.length === 0) {
 | 
			
		||||
        return { quote: undefined, adjustedRate: ZERO_AMOUNT };
 | 
			
		||||
    }
 | 
			
		||||
    const best = twoHopQuotes
 | 
			
		||||
    const best = filteredQuotes
 | 
			
		||||
        .map(quote =>
 | 
			
		||||
            getTwoHopAdjustedRate(side, quote, inputAmount, ethToOutputRate, feeSchedule, exchangeProxyOverhead),
 | 
			
		||||
        )
 | 
			
		||||
        .reduce(
 | 
			
		||||
            (prev, curr, i) =>
 | 
			
		||||
                curr.isGreaterThan(prev.adjustedRate) ? { adjustedRate: curr, quote: twoHopQuotes[i] } : prev,
 | 
			
		||||
                curr.isGreaterThan(prev.adjustedRate) ? { adjustedRate: curr, quote: filteredQuotes[i] } : prev,
 | 
			
		||||
            {
 | 
			
		||||
                adjustedRate: getTwoHopAdjustedRate(
 | 
			
		||||
                    side,
 | 
			
		||||
                    twoHopQuotes[0],
 | 
			
		||||
                    filteredQuotes[0],
 | 
			
		||||
                    inputAmount,
 | 
			
		||||
                    ethToOutputRate,
 | 
			
		||||
                    feeSchedule,
 | 
			
		||||
                    exchangeProxyOverhead,
 | 
			
		||||
                ),
 | 
			
		||||
                quote: twoHopQuotes[0],
 | 
			
		||||
                quote: filteredQuotes[0],
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
    return best;
 | 
			
		||||
 
 | 
			
		||||
@@ -186,6 +186,8 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath
 | 
			
		||||
            return opts.contractAddresses.bancorBridge;
 | 
			
		||||
        case ERC20BridgeSource.Balancer:
 | 
			
		||||
            return opts.contractAddresses.balancerBridge;
 | 
			
		||||
        case ERC20BridgeSource.Cream:
 | 
			
		||||
            return opts.contractAddresses.creamBridge;
 | 
			
		||||
        case ERC20BridgeSource.LiquidityProvider:
 | 
			
		||||
            return (fill.fillData as LiquidityProviderFillData).poolAddress;
 | 
			
		||||
        case ERC20BridgeSource.MultiBridge:
 | 
			
		||||
@@ -250,6 +252,14 @@ export function createBridgeOrder(
 | 
			
		||||
                createBalancerBridgeData(takerToken, balancerFillData.poolAddress),
 | 
			
		||||
            );
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Cream:
 | 
			
		||||
            const creamFillData = (fill as CollapsedFill<BalancerFillData>).fillData!; // tslint:disable-line:no-non-null-assertion
 | 
			
		||||
            makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
 | 
			
		||||
                makerToken,
 | 
			
		||||
                bridgeAddress,
 | 
			
		||||
                createBalancerBridgeData(takerToken, creamFillData.poolAddress),
 | 
			
		||||
            );
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Bancor:
 | 
			
		||||
            const bancorFillData = (fill as CollapsedFill<BancorFillData>).fillData!; // tslint:disable-line:no-non-null-assertion
 | 
			
		||||
            makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import { ERC20BridgeSamplerContract } from '../../wrappers';
 | 
			
		||||
 | 
			
		||||
import { BalancerPoolsCache } from './balancer_utils';
 | 
			
		||||
import { BancorService } from './bancor_service';
 | 
			
		||||
import { CreamPoolsCache } from './cream_utils';
 | 
			
		||||
import { SamplerOperations } from './sampler_operations';
 | 
			
		||||
import { BatchedOperation } from './types';
 | 
			
		||||
 | 
			
		||||
@@ -37,9 +38,10 @@ export class DexOrderSampler extends SamplerOperations {
 | 
			
		||||
        private readonly _samplerOverrides?: SamplerOverrides,
 | 
			
		||||
        provider?: SupportedProvider,
 | 
			
		||||
        balancerPoolsCache?: BalancerPoolsCache,
 | 
			
		||||
        creamPoolsCache?: CreamPoolsCache,
 | 
			
		||||
        getBancorServiceFn?: () => BancorService,
 | 
			
		||||
    ) {
 | 
			
		||||
        super(_samplerContract, provider, balancerPoolsCache, getBancorServiceFn);
 | 
			
		||||
        super(_samplerContract, provider, balancerPoolsCache, creamPoolsCache, getBancorServiceFn);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Type overloads for `executeAsync()`. Could skip this if we would upgrade TS. */
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import { ERC20BridgeSamplerContract } from '../../wrappers';
 | 
			
		||||
import { BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils';
 | 
			
		||||
import { BancorService } from './bancor_service';
 | 
			
		||||
import { MAINNET_SUSHI_SWAP_ROUTER, MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } from './constants';
 | 
			
		||||
import { CreamPoolsCache } from './cream_utils';
 | 
			
		||||
import { getCurveInfosForPair, getSwerveInfosForPair } from './curve_utils';
 | 
			
		||||
import { getKyberReserveIdsForPair } from './kyber_utils';
 | 
			
		||||
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
 | 
			
		||||
@@ -73,6 +74,7 @@ export class SamplerOperations {
 | 
			
		||||
        protected readonly _samplerContract: ERC20BridgeSamplerContract,
 | 
			
		||||
        public readonly provider?: SupportedProvider,
 | 
			
		||||
        public readonly balancerPoolsCache: BalancerPoolsCache = new BalancerPoolsCache(),
 | 
			
		||||
        public readonly creamPoolsCache: CreamPoolsCache = new CreamPoolsCache(),
 | 
			
		||||
        protected readonly getBancorServiceFn?: () => BancorService, // for dependency injection in tests
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
@@ -419,9 +421,10 @@ export class SamplerOperations {
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        takerFillAmounts: BigNumber[],
 | 
			
		||||
        source: ERC20BridgeSource,
 | 
			
		||||
    ): SourceQuoteOperation<BalancerFillData> {
 | 
			
		||||
        return new SamplerContractOperation({
 | 
			
		||||
            source: ERC20BridgeSource.Balancer,
 | 
			
		||||
            source,
 | 
			
		||||
            fillData: { poolAddress },
 | 
			
		||||
            contract: this._samplerContract,
 | 
			
		||||
            function: this._samplerContract.sampleSellsFromBalancer,
 | 
			
		||||
@@ -434,9 +437,10 @@ export class SamplerOperations {
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        makerFillAmounts: BigNumber[],
 | 
			
		||||
        source: ERC20BridgeSource,
 | 
			
		||||
    ): SourceQuoteOperation<BalancerFillData> {
 | 
			
		||||
        return new SamplerContractOperation({
 | 
			
		||||
            source: ERC20BridgeSource.Balancer,
 | 
			
		||||
            source,
 | 
			
		||||
            fillData: { poolAddress },
 | 
			
		||||
            contract: this._samplerContract,
 | 
			
		||||
            function: this._samplerContract.sampleBuysFromBalancer,
 | 
			
		||||
@@ -476,6 +480,38 @@ export class SamplerOperations {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async getCreamSellQuotesOffChainAsync(
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        takerFillAmounts: BigNumber[],
 | 
			
		||||
    ): Promise<Array<Array<DexSample<BalancerFillData>>>> {
 | 
			
		||||
        const pools = await this.creamPoolsCache.getPoolsForPairAsync(takerToken, makerToken);
 | 
			
		||||
        return pools.map(pool =>
 | 
			
		||||
            takerFillAmounts.map(amount => ({
 | 
			
		||||
                source: ERC20BridgeSource.Cream,
 | 
			
		||||
                output: computeBalancerSellQuote(pool, amount),
 | 
			
		||||
                input: amount,
 | 
			
		||||
                fillData: { poolAddress: pool.id },
 | 
			
		||||
            })),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async getCreamBuyQuotesOffChainAsync(
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        makerFillAmounts: BigNumber[],
 | 
			
		||||
    ): Promise<Array<Array<DexSample<BalancerFillData>>>> {
 | 
			
		||||
        const pools = await this.creamPoolsCache.getPoolsForPairAsync(takerToken, makerToken);
 | 
			
		||||
        return pools.map(pool =>
 | 
			
		||||
            makerFillAmounts.map(amount => ({
 | 
			
		||||
                source: ERC20BridgeSource.Cream,
 | 
			
		||||
                output: computeBalancerBuyQuote(pool, amount),
 | 
			
		||||
                input: amount,
 | 
			
		||||
                fillData: { poolAddress: pool.id },
 | 
			
		||||
            })),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public getMStableSellQuotes(
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
@@ -609,11 +645,12 @@ export class SamplerOperations {
 | 
			
		||||
                    const [firstHop, secondHop, buyAmount] = this._samplerContract.getABIDecodedReturnData<
 | 
			
		||||
                        [HopInfo, HopInfo, BigNumber]
 | 
			
		||||
                    >('sampleTwoHopSell', callResults);
 | 
			
		||||
                    // Ensure the hop sources are set even when the buy amount is zero
 | 
			
		||||
                    fillData.firstHopSource = firstHopOps[firstHop.sourceIndex.toNumber()];
 | 
			
		||||
                    fillData.secondHopSource = secondHopOps[secondHop.sourceIndex.toNumber()];
 | 
			
		||||
                    if (buyAmount.isZero()) {
 | 
			
		||||
                        return [ZERO_AMOUNT];
 | 
			
		||||
                    }
 | 
			
		||||
                    fillData.firstHopSource = firstHopOps[firstHop.sourceIndex.toNumber()];
 | 
			
		||||
                    fillData.secondHopSource = secondHopOps[secondHop.sourceIndex.toNumber()];
 | 
			
		||||
                    fillData.firstHopSource.handleCallResults(firstHop.returnData);
 | 
			
		||||
                    fillData.secondHopSource.handleCallResults(secondHop.returnData);
 | 
			
		||||
                    return [buyAmount];
 | 
			
		||||
@@ -1047,7 +1084,25 @@ export class SamplerOperations {
 | 
			
		||||
                            return this.balancerPoolsCache
 | 
			
		||||
                                .getCachedPoolAddressesForPair(takerToken, makerToken)!
 | 
			
		||||
                                .map(poolAddress =>
 | 
			
		||||
                                    this.getBalancerSellQuotes(poolAddress, makerToken, takerToken, takerFillAmounts),
 | 
			
		||||
                                    this.getBalancerSellQuotes(
 | 
			
		||||
                                        poolAddress,
 | 
			
		||||
                                        makerToken,
 | 
			
		||||
                                        takerToken,
 | 
			
		||||
                                        takerFillAmounts,
 | 
			
		||||
                                        ERC20BridgeSource.Balancer,
 | 
			
		||||
                                    ),
 | 
			
		||||
                                );
 | 
			
		||||
                        case ERC20BridgeSource.Cream:
 | 
			
		||||
                            return this.creamPoolsCache
 | 
			
		||||
                                .getCachedPoolAddressesForPair(takerToken, makerToken)!
 | 
			
		||||
                                .map(poolAddress =>
 | 
			
		||||
                                    this.getBalancerSellQuotes(
 | 
			
		||||
                                        poolAddress,
 | 
			
		||||
                                        makerToken,
 | 
			
		||||
                                        takerToken,
 | 
			
		||||
                                        takerFillAmounts,
 | 
			
		||||
                                        ERC20BridgeSource.Cream,
 | 
			
		||||
                                    ),
 | 
			
		||||
                                );
 | 
			
		||||
                        case ERC20BridgeSource.Shell:
 | 
			
		||||
                            return this.getShellSellQuotes(makerToken, takerToken, takerFillAmounts);
 | 
			
		||||
@@ -1138,7 +1193,25 @@ export class SamplerOperations {
 | 
			
		||||
                            return this.balancerPoolsCache
 | 
			
		||||
                                .getCachedPoolAddressesForPair(takerToken, makerToken)!
 | 
			
		||||
                                .map(poolAddress =>
 | 
			
		||||
                                    this.getBalancerBuyQuotes(poolAddress, makerToken, takerToken, makerFillAmounts),
 | 
			
		||||
                                    this.getBalancerBuyQuotes(
 | 
			
		||||
                                        poolAddress,
 | 
			
		||||
                                        makerToken,
 | 
			
		||||
                                        takerToken,
 | 
			
		||||
                                        makerFillAmounts,
 | 
			
		||||
                                        ERC20BridgeSource.Balancer,
 | 
			
		||||
                                    ),
 | 
			
		||||
                                );
 | 
			
		||||
                        case ERC20BridgeSource.Cream:
 | 
			
		||||
                            return this.creamPoolsCache
 | 
			
		||||
                                .getCachedPoolAddressesForPair(takerToken, makerToken)!
 | 
			
		||||
                                .map(poolAddress =>
 | 
			
		||||
                                    this.getBalancerBuyQuotes(
 | 
			
		||||
                                        poolAddress,
 | 
			
		||||
                                        makerToken,
 | 
			
		||||
                                        takerToken,
 | 
			
		||||
                                        makerFillAmounts,
 | 
			
		||||
                                        ERC20BridgeSource.Cream,
 | 
			
		||||
                                    ),
 | 
			
		||||
                                );
 | 
			
		||||
                        case ERC20BridgeSource.Shell:
 | 
			
		||||
                            return this.getShellBuyQuotes(makerToken, takerToken, makerFillAmounts);
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ export enum ERC20BridgeSource {
 | 
			
		||||
    LiquidityProvider = 'LiquidityProvider',
 | 
			
		||||
    MultiBridge = 'MultiBridge',
 | 
			
		||||
    Balancer = 'Balancer',
 | 
			
		||||
    Cream = 'CREAM',
 | 
			
		||||
    Bancor = 'Bancor',
 | 
			
		||||
    MStable = 'mStable',
 | 
			
		||||
    Mooniswap = 'Mooniswap',
 | 
			
		||||
@@ -243,6 +244,11 @@ export interface GetMarketOrdersOpts {
 | 
			
		||||
     * Liquidity sources to exclude. Default is none.
 | 
			
		||||
     */
 | 
			
		||||
    excludedSources: ERC20BridgeSource[];
 | 
			
		||||
    /**
 | 
			
		||||
     * Liquidity sources to exclude when used to calculate the cost of the route.
 | 
			
		||||
     * Default is none.
 | 
			
		||||
     */
 | 
			
		||||
    excludedFeeSources: ERC20BridgeSource[];
 | 
			
		||||
    /**
 | 
			
		||||
     * Liquidity sources to include. Default is none, which allows all supported
 | 
			
		||||
     * sources that aren't excluded by `excludedSources`.
 | 
			
		||||
 
 | 
			
		||||
@@ -504,6 +504,7 @@ describe('DexSampler tests', () => {
 | 
			
		||||
                undefined, // sampler overrides
 | 
			
		||||
                provider,
 | 
			
		||||
                undefined, // balancer cache
 | 
			
		||||
                undefined, // cream cache
 | 
			
		||||
                () => bancorService,
 | 
			
		||||
            );
 | 
			
		||||
            const quotes = await dexOrderSampler.getBancorSellQuotesOffChainAsync(
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ import {
 | 
			
		||||
    SOURCE_FLAGS,
 | 
			
		||||
    ZERO_AMOUNT,
 | 
			
		||||
} from '../src/utils/market_operation_utils/constants';
 | 
			
		||||
import { CreamPoolsCache } from '../src/utils/market_operation_utils/cream_utils';
 | 
			
		||||
import { createFills } from '../src/utils/market_operation_utils/fills';
 | 
			
		||||
import { DexOrderSampler } from '../src/utils/market_operation_utils/sampler';
 | 
			
		||||
import { BATCH_SOURCE_FILTERS } from '../src/utils/market_operation_utils/sampler_operations';
 | 
			
		||||
@@ -55,6 +56,7 @@ const DEFAULT_EXCLUDED = [
 | 
			
		||||
    ERC20BridgeSource.SushiSwap,
 | 
			
		||||
    ERC20BridgeSource.MultiHop,
 | 
			
		||||
    ERC20BridgeSource.Shell,
 | 
			
		||||
    ERC20BridgeSource.Cream,
 | 
			
		||||
    ERC20BridgeSource.Dodo,
 | 
			
		||||
];
 | 
			
		||||
const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
 | 
			
		||||
@@ -323,6 +325,7 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
        [ERC20BridgeSource.SushiSwap]: _.times(NUM_SAMPLES, () => 0),
 | 
			
		||||
        [ERC20BridgeSource.MultiHop]: _.times(NUM_SAMPLES, () => 0),
 | 
			
		||||
        [ERC20BridgeSource.Shell]: _.times(NUM_SAMPLES, () => 0),
 | 
			
		||||
        [ERC20BridgeSource.Cream]: _.times(NUM_SAMPLES, () => 0),
 | 
			
		||||
        [ERC20BridgeSource.Dodo]: _.times(NUM_SAMPLES, () => 0),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -370,6 +373,7 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
        [ERC20BridgeSource.Native]: { order: createOrder() },
 | 
			
		||||
        [ERC20BridgeSource.MultiHop]: {},
 | 
			
		||||
        [ERC20BridgeSource.Shell]: {},
 | 
			
		||||
        [ERC20BridgeSource.Cream]: { poolAddress: randomAddress() },
 | 
			
		||||
        [ERC20BridgeSource.Dodo]: {},
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -411,6 +415,22 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
                DEFAULT_FILL_DATA[ERC20BridgeSource.Balancer],
 | 
			
		||||
            ),
 | 
			
		||||
        ],
 | 
			
		||||
        getCreamSellQuotesOffChainAsync: (_makerToken: string, _takerToken: string, takerFillAmounts: BigNumber[]) => [
 | 
			
		||||
            createSamplesFromRates(
 | 
			
		||||
                ERC20BridgeSource.Cream,
 | 
			
		||||
                takerFillAmounts,
 | 
			
		||||
                createDecreasingRates(takerFillAmounts.length),
 | 
			
		||||
                DEFAULT_FILL_DATA[ERC20BridgeSource.Cream],
 | 
			
		||||
            ),
 | 
			
		||||
        ],
 | 
			
		||||
        getCreamBuyQuotesOffChainAsync: (_makerToken: string, _takerToken: string, makerFillAmounts: BigNumber[]) => [
 | 
			
		||||
            createSamplesFromRates(
 | 
			
		||||
                ERC20BridgeSource.Cream,
 | 
			
		||||
                makerFillAmounts,
 | 
			
		||||
                createDecreasingRates(makerFillAmounts.length).map(r => new BigNumber(1).div(r)),
 | 
			
		||||
                DEFAULT_FILL_DATA[ERC20BridgeSource.Cream],
 | 
			
		||||
            ),
 | 
			
		||||
        ],
 | 
			
		||||
        getBancorSellQuotesOffChainAsync: (_makerToken: string, _takerToken: string, takerFillAmounts: BigNumber[]) =>
 | 
			
		||||
            createSamplesFromRates(
 | 
			
		||||
                ERC20BridgeSource.Bancor,
 | 
			
		||||
@@ -430,6 +450,7 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
            return ops;
 | 
			
		||||
        },
 | 
			
		||||
        balancerPoolsCache: new BalancerPoolsCache(),
 | 
			
		||||
        creamPoolsCache: new CreamPoolsCache(),
 | 
			
		||||
    } as any) as DexOrderSampler;
 | 
			
		||||
 | 
			
		||||
    function replaceSamplerOps(ops: Partial<typeof DEFAULT_OPS> = {}): void {
 | 
			
		||||
@@ -535,6 +556,14 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
 | 
			
		||||
                        return DEFAULT_OPS.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                    getCreamSellQuotesOffChainAsync: (
 | 
			
		||||
                        makerToken: string,
 | 
			
		||||
                        takerToken: string,
 | 
			
		||||
                        takerFillAmounts: BigNumber[],
 | 
			
		||||
                    ) => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
 | 
			
		||||
                        return DEFAULT_OPS.getCreamSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
                await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
 | 
			
		||||
                    ...DEFAULT_OPTS,
 | 
			
		||||
@@ -565,6 +594,14 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
                        args.sources = args.sources.concat(ERC20BridgeSource.Balancer);
 | 
			
		||||
                        return DEFAULT_OPS.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                    getCreamSellQuotesOffChainAsync: (
 | 
			
		||||
                        makerToken: string,
 | 
			
		||||
                        takerToken: string,
 | 
			
		||||
                        takerFillAmounts: BigNumber[],
 | 
			
		||||
                    ) => {
 | 
			
		||||
                        args.sources = args.sources.concat(ERC20BridgeSource.Cream);
 | 
			
		||||
                        return DEFAULT_OPS.getCreamSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
                const registryAddress = randomAddress();
 | 
			
		||||
                const newMarketOperationUtils = new MarketOperationUtils(
 | 
			
		||||
@@ -606,6 +643,14 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
 | 
			
		||||
                        return DEFAULT_OPS.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                    getCreamSellQuotesOffChainAsync: (
 | 
			
		||||
                        makerToken: string,
 | 
			
		||||
                        takerToken: string,
 | 
			
		||||
                        takerFillAmounts: BigNumber[],
 | 
			
		||||
                    ) => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
 | 
			
		||||
                        return DEFAULT_OPS.getCreamSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
                await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
 | 
			
		||||
                    ...DEFAULT_OPTS,
 | 
			
		||||
@@ -637,6 +682,14 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
 | 
			
		||||
                        return DEFAULT_OPS.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                    getCreamSellQuotesOffChainAsync: (
 | 
			
		||||
                        makerToken: string,
 | 
			
		||||
                        takerToken: string,
 | 
			
		||||
                        takerFillAmounts: BigNumber[],
 | 
			
		||||
                    ) => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
 | 
			
		||||
                        return DEFAULT_OPS.getCreamSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
                await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
 | 
			
		||||
                    ...DEFAULT_OPTS,
 | 
			
		||||
@@ -1380,6 +1433,14 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
 | 
			
		||||
                        return DEFAULT_OPS.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                    getCreamBuyQuotesOffChainAsync: (
 | 
			
		||||
                        makerToken: string,
 | 
			
		||||
                        takerToken: string,
 | 
			
		||||
                        makerFillAmounts: BigNumber[],
 | 
			
		||||
                    ) => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
 | 
			
		||||
                        return DEFAULT_OPS.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
                await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
 | 
			
		||||
                    ...DEFAULT_OPTS,
 | 
			
		||||
@@ -1410,6 +1471,14 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
                        args.sources = args.sources.concat(ERC20BridgeSource.Balancer);
 | 
			
		||||
                        return DEFAULT_OPS.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                    getCreamBuyQuotesOffChainAsync: (
 | 
			
		||||
                        makerToken: string,
 | 
			
		||||
                        takerToken: string,
 | 
			
		||||
                        makerFillAmounts: BigNumber[],
 | 
			
		||||
                    ) => {
 | 
			
		||||
                        args.sources = args.sources.concat(ERC20BridgeSource.Cream);
 | 
			
		||||
                        return DEFAULT_OPS.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
                const registryAddress = randomAddress();
 | 
			
		||||
                const newMarketOperationUtils = new MarketOperationUtils(
 | 
			
		||||
@@ -1451,6 +1520,14 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
 | 
			
		||||
                        return DEFAULT_OPS.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                    getCreamBuyQuotesOffChainAsync: (
 | 
			
		||||
                        makerToken: string,
 | 
			
		||||
                        takerToken: string,
 | 
			
		||||
                        makerFillAmounts: BigNumber[],
 | 
			
		||||
                    ) => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
 | 
			
		||||
                        return DEFAULT_OPS.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
                await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
 | 
			
		||||
                    ...DEFAULT_OPTS,
 | 
			
		||||
@@ -1482,6 +1559,14 @@ describe('MarketOperationUtils tests', () => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
 | 
			
		||||
                        return DEFAULT_OPS.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                    getCreamBuyQuotesOffChainAsync: (
 | 
			
		||||
                        makerToken: string,
 | 
			
		||||
                        takerToken: string,
 | 
			
		||||
                        makerFillAmounts: BigNumber[],
 | 
			
		||||
                    ) => {
 | 
			
		||||
                        sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
 | 
			
		||||
                        return DEFAULT_OPS.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
                await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
 | 
			
		||||
                    ...DEFAULT_OPTS,
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,10 @@
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Deploy `DodoBridge` on Mainnet",
 | 
			
		||||
                "pr": 2701
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Deploy `CreamBridge` on Mainnet",
 | 
			
		||||
                "pr": 2715
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,7 @@
 | 
			
		||||
        "sushiswapBridge": "0x47ed0262a0b688dcb836d254c6a2e96b6c48a9f5",
 | 
			
		||||
        "shellBridge": "0x21fb3862eed7911e0f8219a077247b849846728d",
 | 
			
		||||
        "dodoBridge": "0xe9da66965a9344aab2167e6813c03f043cc7a6ca",
 | 
			
		||||
        "creamBridge": "0xb9d4bf2c8dab828f4ffb656acdb6c2b497d44f25",
 | 
			
		||||
        "transformers": {
 | 
			
		||||
            "wethTransformer": "0x68c0bb685099dc7cb5c5ce2b26185945b357383e",
 | 
			
		||||
            "payTakerTransformer": "0x49b9df2c58491764cf40cb052dd4243df63622c7",
 | 
			
		||||
@@ -98,6 +99,7 @@
 | 
			
		||||
        "sushiswapBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "shellBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dodoBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "creamBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "transformers": {
 | 
			
		||||
            "wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437",
 | 
			
		||||
            "payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6",
 | 
			
		||||
@@ -151,6 +153,7 @@
 | 
			
		||||
        "sushiswapBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "shellBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dodoBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "creamBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "transformers": {
 | 
			
		||||
            "wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437",
 | 
			
		||||
            "payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6",
 | 
			
		||||
@@ -204,6 +207,7 @@
 | 
			
		||||
        "sushiswapBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "shellBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dodoBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "creamBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "transformers": {
 | 
			
		||||
            "wethTransformer": "0x9ce35b5ee9e710535e3988e3f8731d9ca9dba17d",
 | 
			
		||||
            "payTakerTransformer": "0x5a53e7b02a83aa9f60ccf4e424f0442c255bc977",
 | 
			
		||||
@@ -257,6 +261,7 @@
 | 
			
		||||
        "sushiswapBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "shellBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "dodoBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "creamBridge": "0x0000000000000000000000000000000000000000",
 | 
			
		||||
        "transformers": {
 | 
			
		||||
            "wethTransformer": "0xc6b0d3c45a6b5092808196cb00df5c357d55e1d5",
 | 
			
		||||
            "payTakerTransformer": "0x7209185959d7227fb77274e1e88151d7c4c368d3",
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,7 @@ export interface ContractAddresses {
 | 
			
		||||
    sushiswapBridge: string;
 | 
			
		||||
    shellBridge: string;
 | 
			
		||||
    dodoBridge: string;
 | 
			
		||||
    creamBridge: string;
 | 
			
		||||
    transformers: {
 | 
			
		||||
        wethTransformer: string;
 | 
			
		||||
        payTakerTransformer: string;
 | 
			
		||||
 
 | 
			
		||||
@@ -325,6 +325,7 @@ export async function runMigrationsAsync(
 | 
			
		||||
            uniswapExchangeFactory: NULL_ADDRESS,
 | 
			
		||||
            mStable: NULL_ADDRESS,
 | 
			
		||||
            shellBridge: NULL_ADDRESS,
 | 
			
		||||
            creamBridge: NULL_ADDRESS,
 | 
			
		||||
            shell: NULL_ADDRESS,
 | 
			
		||||
            weth: etherToken.address,
 | 
			
		||||
        },
 | 
			
		||||
@@ -405,6 +406,7 @@ export async function runMigrationsAsync(
 | 
			
		||||
        sushiswapBridge: NULL_ADDRESS,
 | 
			
		||||
        shellBridge: NULL_ADDRESS,
 | 
			
		||||
        dodoBridge: NULL_ADDRESS,
 | 
			
		||||
        creamBridge: NULL_ADDRESS,
 | 
			
		||||
        exchangeProxy: exchangeProxy.address,
 | 
			
		||||
        exchangeProxyAllowanceTarget: exchangeProxyAllowanceTargetAddress,
 | 
			
		||||
        exchangeProxyTransformerDeployer: txDefaults.from,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										267
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										267
									
								
								yarn.lock
									
									
									
									
									
								
							@@ -1094,6 +1094,242 @@
 | 
			
		||||
  version "0.7.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.2.tgz#b180097bb44a40c3b59efea9cf28df2fe542d518"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/abi@^5.0.1", "@ethersproject/abi@^5.0.5":
 | 
			
		||||
  version "5.0.7"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.7.tgz#79e52452bd3ca2956d0e1c964207a58ad1a0ee7b"
 | 
			
		||||
  integrity sha512-Cqktk+hSIckwP/W8O47Eef60VwmoSC/L3lY0+dIBhQPCNn9E4V7rwmm2aFrNRRDJfFlGuZ1khkQUOc3oBX+niw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/address" "^5.0.4"
 | 
			
		||||
    "@ethersproject/bignumber" "^5.0.7"
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/constants" "^5.0.4"
 | 
			
		||||
    "@ethersproject/hash" "^5.0.4"
 | 
			
		||||
    "@ethersproject/keccak256" "^5.0.3"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    "@ethersproject/properties" "^5.0.3"
 | 
			
		||||
    "@ethersproject/strings" "^5.0.4"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/abstract-provider@^5.0.4":
 | 
			
		||||
  version "5.0.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.0.5.tgz#797a32a8707830af1ad8f833e9c228994d5572b9"
 | 
			
		||||
  integrity sha512-i/CjElAkzV7vQBAeoz+IpjGfcFYEP9eD7j3fzZ0fzTq03DO7PPnR+xkEZ1IoDXGwDS+55aLM1xvLDwB/Lx6IOQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bignumber" "^5.0.7"
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    "@ethersproject/networks" "^5.0.3"
 | 
			
		||||
    "@ethersproject/properties" "^5.0.3"
 | 
			
		||||
    "@ethersproject/transactions" "^5.0.5"
 | 
			
		||||
    "@ethersproject/web" "^5.0.6"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/abstract-signer@^5.0.4":
 | 
			
		||||
  version "5.0.6"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.0.6.tgz#c01211665ab9c9e93988c4783b789712fd93a388"
 | 
			
		||||
  integrity sha512-h8TZBX3pL2Xx9tmsRxfWcaaI+FcJFHWvZ/vNvFjLp8zJ0kPD501LKTt2jo44LZ20N3EW68JMoyEmRQ6bpsn+iA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/abstract-provider" "^5.0.4"
 | 
			
		||||
    "@ethersproject/bignumber" "^5.0.7"
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    "@ethersproject/properties" "^5.0.3"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/address@^5.0.1", "@ethersproject/address@^5.0.4":
 | 
			
		||||
  version "5.0.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.0.5.tgz#2caa65f6b7125015395b1b54c985ee0b27059cc7"
 | 
			
		||||
  integrity sha512-DpkQ6rwk9jTefrRsJzEm6nhRiJd9pvhn1xN0rw5N/jswXG5r7BLk/GVA0mMAVWAsYfvi2xSc5L41FMox43RYEA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bignumber" "^5.0.7"
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/keccak256" "^5.0.3"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    "@ethersproject/rlp" "^5.0.3"
 | 
			
		||||
    bn.js "^4.4.0"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/base64@^5.0.3":
 | 
			
		||||
  version "5.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.0.4.tgz#b0d8fdbf3dda977cf546dcd35725a7b1d5256caa"
 | 
			
		||||
  integrity sha512-4KRykQ7BQMeOXfvio1YITwHjxwBzh92UoXIdzxDE1p53CK28bbHPdsPNYo0wl0El7lJAMpT2SOdL0hhbWRnyIA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/basex@^5.0.3":
 | 
			
		||||
  version "5.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.0.4.tgz#93e1cd11f9a47281da2389de24f88e13e9d90847"
 | 
			
		||||
  integrity sha512-ixIr/kKiAoSzOnSc777AGIOAhKai5Ivqr4HO/Gz+YG+xkfv6kqD6AW4ga9vM20Wwb0QBhh3LoRWTu4V1K+x9Ew==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/properties" "^5.0.3"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/bignumber@^5.0.7":
 | 
			
		||||
  version "5.0.8"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.0.8.tgz#cee33bd8eb0266176def0d371b45274b1d2c4ec0"
 | 
			
		||||
  integrity sha512-KXFVAFKS1jdTXYN8BE5Oj+ZfPMh28iRdFeNGBVT6cUFdtiPVqeXqc0ggvBqA3A1VoFFGgM7oAeaagA393aORHA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    bn.js "^4.4.0"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/bytes@^5.0.4":
 | 
			
		||||
  version "5.0.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.0.5.tgz#688b70000e550de0c97a151a21f15b87d7f97d7c"
 | 
			
		||||
  integrity sha512-IEj9HpZB+ACS6cZ+QQMTqmu/cnUK2fYNE6ms/PVxjoBjoxc6HCraLpam1KuRvreMy0i523PLmjN8OYeikRdcUQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/constants@^5.0.4":
 | 
			
		||||
  version "5.0.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.0.5.tgz#0ed19b002e8404bdf6d135234dc86a7d9bcf9b71"
 | 
			
		||||
  integrity sha512-foaQVmxp2+ik9FrLUCtVrLZCj4M3Ibgkqvh+Xw/vFRSerkjVSYePApaVE5essxhoSlF1U9oXfWY09QI2AXtgKA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bignumber" "^5.0.7"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/contracts@^5.0.1":
 | 
			
		||||
  version "5.0.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.0.5.tgz#64831a341ec8ca225e83ff3e9437c26b970fd5d7"
 | 
			
		||||
  integrity sha512-tFI255lFbmbqMkgnuyhDWHl3yWqttPlReplYuVvDCT/SuvBjLR4ad2uipBlh1fh5X1ipK9ettAoV4S0HKim4Kw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/abi" "^5.0.5"
 | 
			
		||||
    "@ethersproject/abstract-provider" "^5.0.4"
 | 
			
		||||
    "@ethersproject/abstract-signer" "^5.0.4"
 | 
			
		||||
    "@ethersproject/address" "^5.0.4"
 | 
			
		||||
    "@ethersproject/bignumber" "^5.0.7"
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/constants" "^5.0.4"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    "@ethersproject/properties" "^5.0.3"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/hash@^5.0.4":
 | 
			
		||||
  version "5.0.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.0.5.tgz#e383ba2c7941834266fa6e2cf543d2b0c50a9d59"
 | 
			
		||||
  integrity sha512-GpI80/h2HDpfNKpCZoxQJCjOQloGnlD5hM1G+tZe8FQDJhEvFjJoPDuWv+NaYjJfOciKS2Axqc4Q4WamdLoUgg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/keccak256" "^5.0.3"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    "@ethersproject/strings" "^5.0.4"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/keccak256@^5.0.3":
 | 
			
		||||
  version "5.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.0.4.tgz#36ca0a7d1ae2a272da5654cb886776d0c680ef3a"
 | 
			
		||||
  integrity sha512-GNpiOUm9PGUxFNqOxYKDQBM0u68bG9XC9iOulEQ8I0tOx/4qUpgVzvgXL6ugxr0RY554Gz/NQsVqknqPzUcxpQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    js-sha3 "0.5.7"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/logger@^5.0.5":
 | 
			
		||||
  version "5.0.6"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.0.6.tgz#faa484203e86e08be9e07fef826afeef7183fe88"
 | 
			
		||||
  integrity sha512-FrX0Vnb3JZ1md/7GIZfmJ06XOAA8r3q9Uqt9O5orr4ZiksnbpXKlyDzQtlZ5Yv18RS8CAUbiKH9vwidJg1BPmQ==
 | 
			
		||||
 | 
			
		||||
"@ethersproject/networks@^5.0.3":
 | 
			
		||||
  version "5.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.0.4.tgz#6d320a5e15a0cda804f5da88be0ba846156f6eec"
 | 
			
		||||
  integrity sha512-/wHDTRms5mpJ09BoDrbNdFWINzONe05wZRgohCXvEv39rrH/Gd/yAnct8wC0RsW3tmFOgjgQxuBvypIxuUynTw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/properties@^5.0.3":
 | 
			
		||||
  version "5.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.0.4.tgz#a67a1f5a52c30850b5062c861631e73d131f666e"
 | 
			
		||||
  integrity sha512-UdyX3GqBxFt15B0uSESdDNmhvEbK3ACdDXl2soshoPcneXuTswHDeA0LoPlnaZzhbgk4p6jqb4GMms5C26Qu6A==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/providers@^5.0.4":
 | 
			
		||||
  version "5.0.12"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.0.12.tgz#de05e865e130709ea1e0870511eb892bda7d41cb"
 | 
			
		||||
  integrity sha512-bRUEVNth+wGlm2Q0cQprVlixBWumfP9anrgAc3V2CbIh+GKvCwisVO8uRLrZOfOvTNSy6PUJi/Z4D5L+k3NAog==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/abstract-provider" "^5.0.4"
 | 
			
		||||
    "@ethersproject/abstract-signer" "^5.0.4"
 | 
			
		||||
    "@ethersproject/address" "^5.0.4"
 | 
			
		||||
    "@ethersproject/basex" "^5.0.3"
 | 
			
		||||
    "@ethersproject/bignumber" "^5.0.7"
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/constants" "^5.0.4"
 | 
			
		||||
    "@ethersproject/hash" "^5.0.4"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    "@ethersproject/networks" "^5.0.3"
 | 
			
		||||
    "@ethersproject/properties" "^5.0.3"
 | 
			
		||||
    "@ethersproject/random" "^5.0.3"
 | 
			
		||||
    "@ethersproject/rlp" "^5.0.3"
 | 
			
		||||
    "@ethersproject/sha2" "^5.0.3"
 | 
			
		||||
    "@ethersproject/strings" "^5.0.4"
 | 
			
		||||
    "@ethersproject/transactions" "^5.0.5"
 | 
			
		||||
    "@ethersproject/web" "^5.0.6"
 | 
			
		||||
    bech32 "1.1.4"
 | 
			
		||||
    ws "7.2.3"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/random@^5.0.3":
 | 
			
		||||
  version "5.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.0.4.tgz#98f7cf65b0e588cec39ef24843e391ed5004556f"
 | 
			
		||||
  integrity sha512-AIZJhqs6Ba4/+U3lOjt3QZbP6b/kuuGLJUYFUonAgWmkTHwqsCwYnFvnHKQSUuHbXHvErp7WFXFlztx+yMn3kQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/rlp@^5.0.3":
 | 
			
		||||
  version "5.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.0.4.tgz#0090a0271e84ea803016a112a79f5cfd80271a77"
 | 
			
		||||
  integrity sha512-5qrrZad7VTjofxSsm7Zg/7Dr4ZOln4S2CqiDdOuTv6MBKnXj0CiBojXyuDy52M8O3wxH0CyE924hXWTDV1PQWQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/sha2@^5.0.3":
 | 
			
		||||
  version "5.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.0.4.tgz#40f639721a27dbe034b3dee021ba20b054586fec"
 | 
			
		||||
  integrity sha512-0yFhf1mspxAfWdXXoPtK94adUeu1R7/FzAa+DfEiZTc76sz/vHXf0LSIazoR3znYKFny6haBxME+usbvvEcF3A==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    hash.js "1.1.3"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/signing-key@^5.0.4":
 | 
			
		||||
  version "5.0.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.0.5.tgz#acfd06fc05a14180df7e027688bbd23fc4baf782"
 | 
			
		||||
  integrity sha512-Z1wY7JC1HVO4CvQWY2TyTTuAr8xK3bJijZw1a9G92JEmKdv1j255R/0YLBBcFTl2J65LUjtXynNJ2GbArPGi5g==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    "@ethersproject/properties" "^5.0.3"
 | 
			
		||||
    elliptic "6.5.3"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/strings@^5.0.4":
 | 
			
		||||
  version "5.0.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.0.5.tgz#ed7e99a282a02f40757691b04a24cd83f3752195"
 | 
			
		||||
  integrity sha512-JED6WaIV00xM/gvj8vSnd+0VWtDYdidTmavFRCTQakqfz+4tDo6Jz5LHgG+dd45h7ah7ykCHW0C7ZXWEDROCXQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/constants" "^5.0.4"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/transactions@^5.0.5":
 | 
			
		||||
  version "5.0.6"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.0.6.tgz#b8b27938be6e9ed671dbdd35fe98af8b14d0df7c"
 | 
			
		||||
  integrity sha512-htsFhOD+NMBxx676A8ehSuwVV49iqpSB+CkjPZ02tpNew0K6p8g0CZ46Z1ZP946gIHAU80xQ0NACHYrjIUaCFA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/address" "^5.0.4"
 | 
			
		||||
    "@ethersproject/bignumber" "^5.0.7"
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/constants" "^5.0.4"
 | 
			
		||||
    "@ethersproject/keccak256" "^5.0.3"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    "@ethersproject/properties" "^5.0.3"
 | 
			
		||||
    "@ethersproject/rlp" "^5.0.3"
 | 
			
		||||
    "@ethersproject/signing-key" "^5.0.4"
 | 
			
		||||
 | 
			
		||||
"@ethersproject/web@^5.0.6":
 | 
			
		||||
  version "5.0.9"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.0.9.tgz#b08f8295f4bfd4777c8723fe9572f5453b9f03cb"
 | 
			
		||||
  integrity sha512-//QNlv1MSkOII1hv3+HQwWoiVFS+BMVGI0KYeUww4cyrEktnx1QIez5bTSab9s9fWTFaWKNmQNBwMbxAqPuYDw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@ethersproject/base64" "^5.0.3"
 | 
			
		||||
    "@ethersproject/bytes" "^5.0.4"
 | 
			
		||||
    "@ethersproject/logger" "^5.0.5"
 | 
			
		||||
    "@ethersproject/properties" "^5.0.3"
 | 
			
		||||
    "@ethersproject/strings" "^5.0.4"
 | 
			
		||||
 | 
			
		||||
"@evocateur/libnpmaccess@^3.1.2":
 | 
			
		||||
  version "3.1.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@evocateur/libnpmaccess/-/libnpmaccess-3.1.2.tgz#ecf7f6ce6b004e9f942b098d92200be4a4b1c845"
 | 
			
		||||
@@ -3912,6 +4148,11 @@ bcrypt-pbkdf@^1.0.0:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    tweetnacl "^0.14.3"
 | 
			
		||||
 | 
			
		||||
bech32@1.1.4:
 | 
			
		||||
  version "1.1.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9"
 | 
			
		||||
  integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==
 | 
			
		||||
 | 
			
		||||
before-after-hook@^2.0.0:
 | 
			
		||||
  version "2.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635"
 | 
			
		||||
@@ -5511,6 +5752,14 @@ coveralls@^3.0.0:
 | 
			
		||||
    minimist "^1.2.0"
 | 
			
		||||
    request "^2.79.0"
 | 
			
		||||
 | 
			
		||||
cream-sor@^0.3.3:
 | 
			
		||||
  version "0.3.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/cream-sor/-/cream-sor-0.3.3.tgz#ae7ab50c68cfd36a89e2101187ceebbb79e1b14c"
 | 
			
		||||
  integrity sha512-taQSvCUunPhwyebwbjxh1l9NDp39lsre+Q2oRMK+gqzbu+Wlbg5GAquwoV2/GLgzia70gi4x1rJCJsUmc5Kygg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    bignumber.js "^9.0.0"
 | 
			
		||||
    isomorphic-fetch "^2.2.1"
 | 
			
		||||
 | 
			
		||||
create-ecdh@^4.0.0:
 | 
			
		||||
  version "4.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.1.tgz#44223dfed533193ba5ba54e0df5709b89acf1f82"
 | 
			
		||||
@@ -6357,6 +6606,19 @@ elliptic@6.5.2:
 | 
			
		||||
    minimalistic-assert "^1.0.0"
 | 
			
		||||
    minimalistic-crypto-utils "^1.0.0"
 | 
			
		||||
 | 
			
		||||
elliptic@6.5.3:
 | 
			
		||||
  version "6.5.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
 | 
			
		||||
  integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    bn.js "^4.4.0"
 | 
			
		||||
    brorand "^1.0.1"
 | 
			
		||||
    hash.js "^1.0.0"
 | 
			
		||||
    hmac-drbg "^1.0.0"
 | 
			
		||||
    inherits "^2.0.1"
 | 
			
		||||
    minimalistic-assert "^1.0.0"
 | 
			
		||||
    minimalistic-crypto-utils "^1.0.0"
 | 
			
		||||
 | 
			
		||||
elliptic@^6.0.0, elliptic@^6.2.3, elliptic@^6.4.0:
 | 
			
		||||
  version "6.4.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
 | 
			
		||||
@@ -18442,6 +18704,11 @@ write@^0.2.1:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    mkdirp "^0.5.1"
 | 
			
		||||
 | 
			
		||||
ws@7.2.3:
 | 
			
		||||
  version "7.2.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46"
 | 
			
		||||
  integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==
 | 
			
		||||
 | 
			
		||||
ws@^3.0.0:
 | 
			
		||||
  version "3.3.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user