rebasing against development...
This commit is contained in:
		@@ -1,96 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./SamplerUtils.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
 | 
			
		||||
 | 
			
		||||
// Minimal CToken interface
 | 
			
		||||
interface ICToken {
 | 
			
		||||
    function mint(uint mintAmount) external returns (uint);
 | 
			
		||||
    function redeem(uint redeemTokens) external returns (uint);
 | 
			
		||||
    function redeemUnderlying(uint redeemAmount) external returns (uint);
 | 
			
		||||
    function exchangeRateStored() external view returns (uint);
 | 
			
		||||
    function decimals() external view returns (uint8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract CompoundSampler is SamplerUtils {
 | 
			
		||||
    uint256 constant private EXCHANGE_RATE_SCALE = 1e10;
 | 
			
		||||
 | 
			
		||||
    function sampleSellsFromCompound(
 | 
			
		||||
        ICToken cToken,
 | 
			
		||||
        IERC20TokenV06 takerToken,
 | 
			
		||||
        IERC20TokenV06 makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        // Exchange rate is scaled by 1 * 10^(18 - 8 + Underlying Token Decimals
 | 
			
		||||
        uint256 exchangeRate = cToken.exchangeRateStored();
 | 
			
		||||
        uint256 cTokenDecimals = uint256(cToken.decimals());
 | 
			
		||||
 | 
			
		||||
        if (address(makerToken) == address(cToken)) {
 | 
			
		||||
            // mint
 | 
			
		||||
            for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
                makerTokenAmounts[i] = (takerTokenAmounts[i] * EXCHANGE_RATE_SCALE * 10 ** cTokenDecimals) / exchangeRate;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } else if (address(takerToken) == address(cToken)) {
 | 
			
		||||
            // redeem
 | 
			
		||||
            for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
                makerTokenAmounts[i] = (takerTokenAmounts[i] * exchangeRate) / (EXCHANGE_RATE_SCALE * 10 ** cTokenDecimals);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function sampleBuysFromCompound(
 | 
			
		||||
        ICToken cToken,
 | 
			
		||||
        IERC20TokenV06 takerToken,
 | 
			
		||||
        IERC20TokenV06 makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        // Exchange rate is scaled by 1 * 10^(18 - 8 + Underlying Token Decimals
 | 
			
		||||
        uint256 exchangeRate = cToken.exchangeRateStored();
 | 
			
		||||
        uint256 cTokenDecimals = uint256(cToken.decimals());
 | 
			
		||||
 | 
			
		||||
        if (address(makerToken) == address(cToken)) {
 | 
			
		||||
            // mint
 | 
			
		||||
            for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
                takerTokenAmounts[i] = makerTokenAmounts[i] * exchangeRate / (EXCHANGE_RATE_SCALE * 10 ** cTokenDecimals);
 | 
			
		||||
            }
 | 
			
		||||
        } else if (address(takerToken) == address(cToken)) {
 | 
			
		||||
            // redeem
 | 
			
		||||
            for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
                takerTokenAmounts[i] = (makerTokenAmounts[i] * EXCHANGE_RATE_SCALE * 10 ** cTokenDecimals)/exchangeRate;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,95 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./BalancerSampler.sol";
 | 
			
		||||
import "./BalancerV2Sampler.sol";
 | 
			
		||||
import "./BancorSampler.sol";
 | 
			
		||||
import "./CompoundSampler.sol";
 | 
			
		||||
import "./CurveSampler.sol";
 | 
			
		||||
import "./DODOSampler.sol";
 | 
			
		||||
import "./DODOV2Sampler.sol";
 | 
			
		||||
import "./KyberSampler.sol";
 | 
			
		||||
import "./KyberDmmSampler.sol";
 | 
			
		||||
import "./LidoSampler.sol";
 | 
			
		||||
import "./LiquidityProviderSampler.sol";
 | 
			
		||||
import "./MakerPSMSampler.sol";
 | 
			
		||||
import "./MultiBridgeSampler.sol";
 | 
			
		||||
import "./MStableSampler.sol";
 | 
			
		||||
import "./MooniswapSampler.sol";
 | 
			
		||||
import "./NativeOrderSampler.sol";
 | 
			
		||||
import "./ShellSampler.sol";
 | 
			
		||||
import "./SmoothySampler.sol";
 | 
			
		||||
import "./TwoHopSampler.sol";
 | 
			
		||||
import "./UniswapSampler.sol";
 | 
			
		||||
import "./UniswapV2Sampler.sol";
 | 
			
		||||
import "./UniswapV3Sampler.sol";
 | 
			
		||||
import "./UtilitySampler.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ERC20BridgeSampler is
 | 
			
		||||
    BalancerSampler,
 | 
			
		||||
    BalancerV2Sampler,
 | 
			
		||||
    BancorSampler,
 | 
			
		||||
    CompoundSampler,
 | 
			
		||||
    CurveSampler,
 | 
			
		||||
    DODOSampler,
 | 
			
		||||
    DODOV2Sampler,
 | 
			
		||||
    KyberSampler,
 | 
			
		||||
    KyberDmmSampler,
 | 
			
		||||
    LidoSampler,
 | 
			
		||||
    LiquidityProviderSampler,
 | 
			
		||||
    MakerPSMSampler,
 | 
			
		||||
    MStableSampler,
 | 
			
		||||
    MooniswapSampler,
 | 
			
		||||
    MultiBridgeSampler,
 | 
			
		||||
    NativeOrderSampler,
 | 
			
		||||
    ShellSampler,
 | 
			
		||||
    SmoothySampler,
 | 
			
		||||
    TwoHopSampler,
 | 
			
		||||
    UniswapSampler,
 | 
			
		||||
    UniswapV2Sampler,
 | 
			
		||||
    UniswapV3Sampler,
 | 
			
		||||
    UtilitySampler
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    struct CallResults {
 | 
			
		||||
        bytes data;
 | 
			
		||||
        bool success;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Call multiple public functions on this contract in a single transaction.
 | 
			
		||||
    /// @param callDatas ABI-encoded call data for each function call.
 | 
			
		||||
    /// @return callResults ABI-encoded results data for each call.
 | 
			
		||||
    function batchCall(bytes[] calldata callDatas)
 | 
			
		||||
        external
 | 
			
		||||
        returns (CallResults[] memory callResults)
 | 
			
		||||
    {
 | 
			
		||||
        callResults = new CallResults[](callDatas.length);
 | 
			
		||||
        for (uint256 i = 0; i != callDatas.length; ++i) {
 | 
			
		||||
            callResults[i].success = true;
 | 
			
		||||
            if (callDatas[i].length == 0) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            (callResults[i].success, callResults[i].data) = address(this).call(callDatas[i]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,179 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
interface IKyberDmmPool {
 | 
			
		||||
 | 
			
		||||
    function totalSupply()
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IKyberDmmFactory {
 | 
			
		||||
 | 
			
		||||
    function getPools(address token0, address token1)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address[] memory _tokenPools);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IKyberDmmRouter {
 | 
			
		||||
 | 
			
		||||
    function factory() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    function getAmountsOut(uint256 amountIn, address[] calldata pools, address[] calldata path)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory amounts);
 | 
			
		||||
 | 
			
		||||
    function getAmountsIn(uint256 amountOut, address[] calldata pools, address[] calldata path)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory amounts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract KyberDmmSampler
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Gas limit for KyberDmm calls.
 | 
			
		||||
    uint256 constant private KYBER_DMM_CALL_GAS = 150e3; // 150k
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from KyberDmm.
 | 
			
		||||
    /// @param router Router to look up tokens and amounts
 | 
			
		||||
    /// @param path Token route. Should be takerToken -> makerToken
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return pools The pool addresses involved in the multi path trade
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromKyberDmm(
 | 
			
		||||
        address router,
 | 
			
		||||
        address[] memory path,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (address[] memory pools, uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        pools = _getKyberDmmPools(router, path);
 | 
			
		||||
        if (pools.length == 0) {
 | 
			
		||||
            return (pools, makerTokenAmounts);
 | 
			
		||||
        }
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            try
 | 
			
		||||
                IKyberDmmRouter(router).getAmountsOut
 | 
			
		||||
                    {gas: KYBER_DMM_CALL_GAS}
 | 
			
		||||
                    (takerTokenAmounts[i], pools, path)
 | 
			
		||||
                returns (uint256[] memory amounts)
 | 
			
		||||
            {
 | 
			
		||||
                makerTokenAmounts[i] = amounts[path.length - 1];
 | 
			
		||||
                // Break early if there are 0 amounts
 | 
			
		||||
                if (makerTokenAmounts[i] == 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from KyberDmm.
 | 
			
		||||
    /// @param router Router to look up tokens and amounts
 | 
			
		||||
    /// @param path Token route. Should be takerToken -> makerToken.
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return pools The pool addresses involved in the multi path trade
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromKyberDmm(
 | 
			
		||||
        address router,
 | 
			
		||||
        address[] memory path,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (address[] memory pools, uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        pools = _getKyberDmmPools(router, path);
 | 
			
		||||
        if (pools.length == 0) {
 | 
			
		||||
            return (pools, takerTokenAmounts);
 | 
			
		||||
        }
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            try
 | 
			
		||||
                IKyberDmmRouter(router).getAmountsIn
 | 
			
		||||
                    {gas: KYBER_DMM_CALL_GAS}
 | 
			
		||||
                    (makerTokenAmounts[i], pools, path)
 | 
			
		||||
                returns (uint256[] memory amounts)
 | 
			
		||||
            {
 | 
			
		||||
                takerTokenAmounts[i] = amounts[0];
 | 
			
		||||
                // Break early if there are 0 amounts
 | 
			
		||||
                if (takerTokenAmounts[i] == 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _getKyberDmmPools(
 | 
			
		||||
        address router,
 | 
			
		||||
        address[] memory path
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (address[] memory pools)
 | 
			
		||||
    {
 | 
			
		||||
        IKyberDmmFactory factory = IKyberDmmFactory(IKyberDmmRouter(router).factory());
 | 
			
		||||
        pools = new address[](path.length - 1);
 | 
			
		||||
        for (uint256 i = 0; i < pools.length; i++) {
 | 
			
		||||
            // find the best pool
 | 
			
		||||
            address[] memory allPools;
 | 
			
		||||
            try
 | 
			
		||||
                factory.getPools
 | 
			
		||||
                    {gas: KYBER_DMM_CALL_GAS}
 | 
			
		||||
                    (path[i], path[i + 1])
 | 
			
		||||
                returns (address[] memory allPools)
 | 
			
		||||
            {
 | 
			
		||||
                if (allPools.length == 0) {
 | 
			
		||||
                    return new address[](0);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                uint256 maxSupply = 0;
 | 
			
		||||
                for (uint256 j = 0; j < allPools.length; j++) {
 | 
			
		||||
                    uint256 totalSupply = IKyberDmmPool(allPools[j]).totalSupply();
 | 
			
		||||
                    if (totalSupply > maxSupply) {
 | 
			
		||||
                        maxSupply = totalSupply;
 | 
			
		||||
                        pools[i] = allPools[j];
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                return new address[](0);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,95 +0,0 @@
 | 
			
		||||
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
 | 
			
		||||
 | 
			
		||||
contract UtilitySampler {
 | 
			
		||||
 | 
			
		||||
    using LibERC20TokenV06 for IERC20TokenV06;
 | 
			
		||||
 | 
			
		||||
    IERC20TokenV06 private immutable UTILITY_ETH_ADDRESS = IERC20TokenV06(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
 | 
			
		||||
 | 
			
		||||
    function getTokenDecimals(IERC20TokenV06[] memory tokens)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory decimals)
 | 
			
		||||
    {
 | 
			
		||||
        decimals = new uint256[](tokens.length);
 | 
			
		||||
        for (uint256 i = 0; i != tokens.length; i++) {
 | 
			
		||||
            decimals[i] = tokens[i] == UTILITY_ETH_ADDRESS
 | 
			
		||||
                ? 18
 | 
			
		||||
                : tokens[i].compatDecimals();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getBalanceOf(IERC20TokenV06[] memory tokens, address account)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory balances)
 | 
			
		||||
    {
 | 
			
		||||
        balances = new uint256[](tokens.length);
 | 
			
		||||
        for (uint256 i = 0; i != tokens.length; i++) {
 | 
			
		||||
            balances[i] = tokens[i] == UTILITY_ETH_ADDRESS
 | 
			
		||||
                ? account.balance
 | 
			
		||||
                : tokens[i].compatBalanceOf(account);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getAllowanceOf(IERC20TokenV06[] memory tokens, address account, address spender)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory allowances)
 | 
			
		||||
    {
 | 
			
		||||
        allowances = new uint256[](tokens.length);
 | 
			
		||||
        for (uint256 i = 0; i != tokens.length; i++) {
 | 
			
		||||
            allowances[i] = tokens[i] == UTILITY_ETH_ADDRESS
 | 
			
		||||
                ? 0
 | 
			
		||||
                : tokens[i].compatAllowance(account, spender);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function isContract(address account)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 size;
 | 
			
		||||
        assembly { size := extcodesize(account) }
 | 
			
		||||
        return size > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getGasLeft()
 | 
			
		||||
        public
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        return gasleft();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getBlockNumber()
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        return block.number;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,57 +0,0 @@
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { ZERO_AMOUNT } from '../constants';
 | 
			
		||||
export interface AaveInfo {
 | 
			
		||||
    lendingPool: string;
 | 
			
		||||
    aToken: string;
 | 
			
		||||
    underlyingToken: string;
 | 
			
		||||
}
 | 
			
		||||
// tslint:disable-next-line:no-unnecessary-class
 | 
			
		||||
export class AaveV2Sampler {
 | 
			
		||||
    public static sampleSellsFromAaveV2(
 | 
			
		||||
        aaveInfo: AaveInfo,
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        takerTokenAmounts: BigNumber[],
 | 
			
		||||
    ): BigNumber[] {
 | 
			
		||||
        // Deposit/Withdrawal underlying <-> aToken is always 1:1
 | 
			
		||||
        if (
 | 
			
		||||
            (takerToken.toLowerCase() === aaveInfo.aToken.toLowerCase() &&
 | 
			
		||||
                makerToken.toLowerCase() === aaveInfo.underlyingToken.toLowerCase()) ||
 | 
			
		||||
            (takerToken.toLowerCase() === aaveInfo.underlyingToken.toLowerCase() &&
 | 
			
		||||
                makerToken.toLowerCase() === aaveInfo.aToken.toLowerCase())
 | 
			
		||||
        ) {
 | 
			
		||||
            return takerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Not matching the reserve return 0 results
 | 
			
		||||
        const numSamples = takerTokenAmounts.length;
 | 
			
		||||
 | 
			
		||||
        const makerTokenAmounts = new Array(numSamples);
 | 
			
		||||
        makerTokenAmounts.fill(ZERO_AMOUNT);
 | 
			
		||||
        return makerTokenAmounts;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static sampleBuysFromAaveV2(
 | 
			
		||||
        aaveInfo: AaveInfo,
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        makerTokenAmounts: BigNumber[],
 | 
			
		||||
    ): BigNumber[] {
 | 
			
		||||
        // Deposit/Withdrawal underlying <-> aToken is always 1:1
 | 
			
		||||
        if (
 | 
			
		||||
            (takerToken.toLowerCase() === aaveInfo.aToken.toLowerCase() &&
 | 
			
		||||
                makerToken.toLowerCase() === aaveInfo.underlyingToken.toLowerCase()) ||
 | 
			
		||||
            (takerToken.toLowerCase() === aaveInfo.underlyingToken.toLowerCase() &&
 | 
			
		||||
                makerToken.toLowerCase() === aaveInfo.aToken.toLowerCase())
 | 
			
		||||
        ) {
 | 
			
		||||
            return makerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Not matching the reserve return 0 results
 | 
			
		||||
        const numSamples = makerTokenAmounts.length;
 | 
			
		||||
        const takerTokenAmounts = new Array(numSamples);
 | 
			
		||||
        takerTokenAmounts.fill(ZERO_AMOUNT);
 | 
			
		||||
        return takerTokenAmounts;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -23,7 +23,6 @@ import {
 | 
			
		||||
    CalldataInfo,
 | 
			
		||||
    ExchangeProxyContractOpts,
 | 
			
		||||
    MarketBuySwapQuote,
 | 
			
		||||
    MarketOperation,
 | 
			
		||||
    MarketSellSwapQuote,
 | 
			
		||||
    SwapQuote,
 | 
			
		||||
    SwapQuoteConsumerBase,
 | 
			
		||||
@@ -39,7 +38,6 @@ import {
 | 
			
		||||
    SwapQuoteGenericBridgeOrder,
 | 
			
		||||
    SwapQuoteOrder,
 | 
			
		||||
} from '../types';
 | 
			
		||||
import { assert } from '../utils/assert';
 | 
			
		||||
import { valueByChainId } from '../utils/utils';
 | 
			
		||||
import {
 | 
			
		||||
    NATIVE_FEE_TOKEN_BY_CHAIN_ID,
 | 
			
		||||
 
 | 
			
		||||
@@ -430,6 +430,7 @@ export const POLYGON_TOKENS = {
 | 
			
		||||
    WBTC: '0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6',
 | 
			
		||||
    WMATIC: '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270',
 | 
			
		||||
    WETH: '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619',
 | 
			
		||||
    nUSD: '0xb6c473756050de474286bed418b77aeac39b02af',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const AVALANCHE_TOKENS = {
 | 
			
		||||
@@ -449,7 +450,6 @@ export const AVALANCHE_TOKENS = {
 | 
			
		||||
    aWETH: '0x53f7c5869a859f0aec3d334ee8b4cf01e3492f21',
 | 
			
		||||
    MIM: '0x130966628846bfd36ff31a822705796e8cb8c18d',
 | 
			
		||||
    DAI: '0xd586e7f844cea2f87f50152665bcbc2c279d8d70',
 | 
			
		||||
    USDT: '0xc7198437980c041c805a1edcba50c1ce5db95118',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const CELO_TOKENS = {
 | 
			
		||||
@@ -682,5 +682,4 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: Omit<GetMarketOrdersOpts, 'gasPrice
 | 
			
		||||
    shouldGenerateQuoteReport: true,
 | 
			
		||||
    shouldIncludePriceComparisonsReport: false,
 | 
			
		||||
    tokenAdjacencyGraph: { default: [] },
 | 
			
		||||
    neonRouterNumSamples: 14,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -5,7 +5,6 @@ import { BigNumber, hexUtils } from '@0x/utils';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
import { performance } from 'perf_hooks';
 | 
			
		||||
 | 
			
		||||
import { DEFAULT_INFO_LOGGER } from '../../constants';
 | 
			
		||||
import { NativeOrderWithFillableAmounts } from '../native_orders';
 | 
			
		||||
import { MarketOperation } from '../../types';
 | 
			
		||||
import { VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID } from '../market_operation_utils/constants';
 | 
			
		||||
@@ -14,7 +13,7 @@ import { VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID, ZERO_AMOUNT } from './constants';
 | 
			
		||||
import { dexSamplesToFills, ethToOutputAmount, nativeOrdersToFills } from './fills';
 | 
			
		||||
import { DEFAULT_PATH_PENALTY_OPTS, Path, PathPenaltyOpts } from './path';
 | 
			
		||||
import { getRate } from './rate_utils';
 | 
			
		||||
import { DexSample, ERC20BridgeSource, Fill } from './types';
 | 
			
		||||
import { DexSample, ERC20BridgeSource, Fill, SamplerMetrics } from './types';
 | 
			
		||||
 | 
			
		||||
// tslint:disable: prefer-for-of custom-no-magic-numbers completed-docs no-bitwise
 | 
			
		||||
 | 
			
		||||
@@ -403,7 +402,6 @@ export function findOptimalRustPathFromSamples(
 | 
			
		||||
        nativeOrders,
 | 
			
		||||
        input,
 | 
			
		||||
        opts,
 | 
			
		||||
        fees,
 | 
			
		||||
        neonRouterNumSamples,
 | 
			
		||||
        vipSourcesSet,
 | 
			
		||||
    );
 | 
			
		||||
 
 | 
			
		||||
@@ -1,36 +0,0 @@
 | 
			
		||||
import { BigNumber, logUtils, NULL_BYTES } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { ERC20BridgeSource, FillData, SourceQuoteOperation } from './types';
 | 
			
		||||
 | 
			
		||||
interface SamplerNoOperationCall {
 | 
			
		||||
    callback: () => BigNumber[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SamplerNoOperation can be used for sources where we already have all the necessary information
 | 
			
		||||
 * required to perform the sample operations, without needing access to any on-chain data. Using a noop sample
 | 
			
		||||
 * you can skip the eth_call, and just calculate the results directly in typescript land.
 | 
			
		||||
 */
 | 
			
		||||
export class SamplerNoOperation<TFillData extends FillData = FillData> implements SourceQuoteOperation<TFillData> {
 | 
			
		||||
    public readonly source: ERC20BridgeSource;
 | 
			
		||||
    public fillData: TFillData;
 | 
			
		||||
    private readonly _callback: () => BigNumber[];
 | 
			
		||||
 | 
			
		||||
    constructor(opts: { source: ERC20BridgeSource; fillData?: TFillData } & SamplerNoOperationCall) {
 | 
			
		||||
        this.source = opts.source;
 | 
			
		||||
        this.fillData = opts.fillData || ({} as TFillData); // tslint:disable-line:no-object-literal-type-assertion
 | 
			
		||||
        this._callback = opts.callback;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // tslint:disable-next-line:prefer-function-over-method
 | 
			
		||||
    public encodeCall(): string {
 | 
			
		||||
        return NULL_BYTES;
 | 
			
		||||
    }
 | 
			
		||||
    public handleCallResults(_callResults: string): BigNumber[] {
 | 
			
		||||
        return this._callback();
 | 
			
		||||
    }
 | 
			
		||||
    public handleRevert(_callResults: string): BigNumber[] {
 | 
			
		||||
        logUtils.warn(`SamplerNoOperation: ${this.source} reverted`);
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,5 @@
 | 
			
		||||
import {
 | 
			
		||||
    FillQuoteTransformerLimitOrderInfo,
 | 
			
		||||
    FillQuoteTransformerOrderType,
 | 
			
		||||
    FillQuoteTransformerRfqOrderInfo,
 | 
			
		||||
    LimitOrderFields,
 | 
			
		||||
    RfqOrderFields,
 | 
			
		||||
    Signature,
 | 
			
		||||
@@ -12,7 +10,7 @@ import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { Address, Bytes, RfqFirmQuoteValidator, RfqRequestOpts } from '../../types';
 | 
			
		||||
import { NativeOrderWithFillableAmounts } from '../native_orders';
 | 
			
		||||
import { QuoteRequestor } from '../../utils/quote_requestor';
 | 
			
		||||
import { PriceComparisonsReport, QuoteReport } from '../quote_report_generator';
 | 
			
		||||
import { ExtendedQuoteReportSources, PriceComparisonsReport, QuoteReport } from '../quote_report_generator';
 | 
			
		||||
 | 
			
		||||
import { SourceFilters } from './source_filters';
 | 
			
		||||
 | 
			
		||||
@@ -429,6 +427,37 @@ export interface GetMarketOrdersOpts {
 | 
			
		||||
     * Gas price to use for quote
 | 
			
		||||
     */
 | 
			
		||||
    gasPrice: BigNumber;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sampler metrics for recording data on the sampler service and operations
 | 
			
		||||
     */
 | 
			
		||||
    samplerMetrics?: SamplerMetrics;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SamplerMetrics {
 | 
			
		||||
    /**
 | 
			
		||||
     * Logs the gas information performed during a sampler call.
 | 
			
		||||
     *
 | 
			
		||||
     * @param data.gasBefore The gas remaining measured before any operations have been performed
 | 
			
		||||
     * @param data.gasAfter The gas remaining measured after all operations have been performed
 | 
			
		||||
     */
 | 
			
		||||
    logGasDetails(data: { gasBefore: BigNumber; gasAfter: BigNumber }): void;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Logs the block number
 | 
			
		||||
     *
 | 
			
		||||
     * @param blockNumber block number of the sampler call
 | 
			
		||||
     */
 | 
			
		||||
    logBlockNumber(blockNumber: BigNumber): void;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Logs the routing timings
 | 
			
		||||
     *
 | 
			
		||||
     * @param data.router The router type (neon-router or js)
 | 
			
		||||
     * @param data.type The type of timing being recorded (e.g total timing, all sources timing or vip timing)
 | 
			
		||||
     * @param data.timingMs The timing in milliseconds
 | 
			
		||||
     */
 | 
			
		||||
    logRouterDetails(data: { router: 'neon-router' | 'js'; type: 'all' | 'vip' | 'total'; timingMs: number }): void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -461,6 +490,7 @@ export interface OptimizerResult {
 | 
			
		||||
 | 
			
		||||
export interface OptimizerResultWithReport extends OptimizerResult {
 | 
			
		||||
    quoteReport?: QuoteReport;
 | 
			
		||||
    extendedQuoteReportSources?: ExtendedQuoteReportSources;
 | 
			
		||||
    priceComparisonsReport?: PriceComparisonsReport;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import {
 | 
			
		||||
    OptimizedNativeOrder,
 | 
			
		||||
} from './market_operation_utils/types';
 | 
			
		||||
import { NativeOrderWithFillableAmounts } from './native_orders';
 | 
			
		||||
import { QuoteRequestor } from './quote_requestor';
 | 
			
		||||
import { QuoteRequestor, V4RFQIndicativeQuoteMM } from './quote_requestor';
 | 
			
		||||
 | 
			
		||||
export interface QuoteReportEntryBase {
 | 
			
		||||
    liquiditySource: ERC20BridgeSource;
 | 
			
		||||
@@ -179,6 +179,107 @@ export function generateQuoteReport(opts: {
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Generates a report of sources considered while computing the optimized
 | 
			
		||||
 * swap quote, the sources ultimately included in the computed quote. This
 | 
			
		||||
 * extende version incudes all considered quotes, not only native liquidity.
 | 
			
		||||
 */
 | 
			
		||||
export function generateExtendedQuoteReportSources(
 | 
			
		||||
    marketOperation: MarketOperation,
 | 
			
		||||
    inputToken: Address,
 | 
			
		||||
    outputToken: Address,
 | 
			
		||||
    rawHopQuotes: RawHopQuotes[],
 | 
			
		||||
    hops: OptimizedHop[],
 | 
			
		||||
    amount: BigNumber,
 | 
			
		||||
    comparisonPrice?: BigNumber | undefined,
 | 
			
		||||
    quoteRequestor?: QuoteRequestor,
 | 
			
		||||
): ExtendedQuoteReportSources {
 | 
			
		||||
    const sourcesConsidered: ExtendedQuoteReportEntry[] = [];
 | 
			
		||||
 | 
			
		||||
    // NativeOrders
 | 
			
		||||
    sourcesConsidered.push(
 | 
			
		||||
        ...quotes.nativeOrders.map(order =>
 | 
			
		||||
            nativeOrderToReportEntry(
 | 
			
		||||
                order.type,
 | 
			
		||||
                order as any,
 | 
			
		||||
                order.fillableTakerAmount,
 | 
			
		||||
                comparisonPrice,
 | 
			
		||||
                quoteRequestor,
 | 
			
		||||
            ),
 | 
			
		||||
        ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // IndicativeQuotes
 | 
			
		||||
    sourcesConsidered.push(
 | 
			
		||||
        ...quotes.rfqtIndicativeQuotes.map(order => indicativeQuoteToReportEntry(order, comparisonPrice)),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // MultiHop
 | 
			
		||||
    sourcesConsidered.push(...quotes.twoHopQuotes.map(quote => multiHopSampleToReportSource(quote, marketOperation)));
 | 
			
		||||
 | 
			
		||||
    // Dex Quotes
 | 
			
		||||
    sourcesConsidered.push(
 | 
			
		||||
        ..._.flatten(
 | 
			
		||||
            quotes.dexQuotes.map(dex =>
 | 
			
		||||
                dex
 | 
			
		||||
                    .filter(quote => isDexSampleForTotalAmount(quote, marketOperation, amount))
 | 
			
		||||
                    .map(quote => dexSampleToReportSource(quote, marketOperation)),
 | 
			
		||||
            ),
 | 
			
		||||
        ),
 | 
			
		||||
    );
 | 
			
		||||
    const sourcesConsideredIndexed = sourcesConsidered.map(
 | 
			
		||||
        (quote, index): ExtendedQuoteReportIndexedEntry => {
 | 
			
		||||
            return {
 | 
			
		||||
                ...quote,
 | 
			
		||||
                quoteEntryIndex: index,
 | 
			
		||||
                isDelivered: false,
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
    let sourcesDelivered;
 | 
			
		||||
    if (Array.isArray(liquidityDelivered)) {
 | 
			
		||||
        // create easy way to look up fillable amounts
 | 
			
		||||
        const nativeOrderSignaturesToFillableAmounts = _.fromPairs(
 | 
			
		||||
            quotes.nativeOrders.map(o => {
 | 
			
		||||
                return [_nativeDataToId(o), o.fillableTakerAmount];
 | 
			
		||||
            }),
 | 
			
		||||
        );
 | 
			
		||||
        // map sources delivered
 | 
			
		||||
        sourcesDelivered = liquidityDelivered.map(collapsedFill => {
 | 
			
		||||
            if (_isNativeOrderFromCollapsedFill(collapsedFill)) {
 | 
			
		||||
                return nativeOrderToReportEntry(
 | 
			
		||||
                    collapsedFill.type,
 | 
			
		||||
                    collapsedFill.fillData,
 | 
			
		||||
                    nativeOrderSignaturesToFillableAmounts[_nativeDataToId(collapsedFill.fillData)],
 | 
			
		||||
                    comparisonPrice,
 | 
			
		||||
                    quoteRequestor,
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                return dexSampleToReportSource(collapsedFill, marketOperation);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    } else {
 | 
			
		||||
        sourcesDelivered = [
 | 
			
		||||
            // tslint:disable-next-line: no-unnecessary-type-assertion
 | 
			
		||||
            multiHopSampleToReportSource(liquidityDelivered as DexSample<MultiHopFillData>, marketOperation),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
    const sourcesDeliveredIndexed = sourcesDelivered.map(
 | 
			
		||||
        (quote, index): ExtendedQuoteReportIndexedEntry => {
 | 
			
		||||
            return {
 | 
			
		||||
                ...quote,
 | 
			
		||||
                quoteEntryIndex: index,
 | 
			
		||||
                isDelivered: false,
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        sourcesConsidered: sourcesConsideredIndexed,
 | 
			
		||||
        sourcesDelivered: sourcesDeliveredIndexed,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function dexSampleToReportSource(
 | 
			
		||||
    side: MarketOperation,
 | 
			
		||||
    sample: DexSample,
 | 
			
		||||
@@ -222,19 +323,19 @@ export function nativeOrderToReportEntry(
 | 
			
		||||
        signature = order.signature;
 | 
			
		||||
        [makerAmount, takerAmount] = [nativeOrder.makerAmount, nativeOrder.takerAmount];
 | 
			
		||||
    }
 | 
			
		||||
    const isRfqt = order.type === FillQuoteTransformerOrderType.Rfq;
 | 
			
		||||
    const isRFQ = order.type === FillQuoteTransformerOrderType.Rfq;
 | 
			
		||||
    // if we find this is an rfqt order, label it as such and associate makerUri
 | 
			
		||||
    const rfqtMakerUri =
 | 
			
		||||
        isRfqt && quoteRequestor ? quoteRequestor.getMakerUriForSignature(signature) : '';
 | 
			
		||||
        isRFQ && quoteRequestor ? quoteRequestor.getMakerUriForSignature(signature) : '';
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        makerAmount,
 | 
			
		||||
        takerAmount,
 | 
			
		||||
        isRfqt,
 | 
			
		||||
        isRFQ,
 | 
			
		||||
        fillableTakerAmount,
 | 
			
		||||
        liquiditySource: ERC20BridgeSource.Native,
 | 
			
		||||
        fillData: {},
 | 
			
		||||
        ...(isRfqt
 | 
			
		||||
        ...(isRFQ
 | 
			
		||||
            ? {
 | 
			
		||||
                makerUri: rfqtMakerUri,
 | 
			
		||||
                nativeOrder,
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,8 @@ export function valueByChainId<T>(rest: Partial<{ [key in ChainId]: T }>, defaul
 | 
			
		||||
        [ChainId.PolygonMumbai]: defaultValue,
 | 
			
		||||
        [ChainId.Avalanche]: defaultValue,
 | 
			
		||||
        [ChainId.Fantom]: defaultValue,
 | 
			
		||||
        [ChainId.Celo]: defaultValue,
 | 
			
		||||
        [ChainId.Optimism]: defaultValue,
 | 
			
		||||
        ...(rest || {}),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								yarn.lock
									
									
									
									
									
								
							@@ -6525,9 +6525,9 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2:
 | 
			
		||||
    readable-stream "^2.3.6"
 | 
			
		||||
 | 
			
		||||
follow-redirects@^1.14.4:
 | 
			
		||||
  version "1.14.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381"
 | 
			
		||||
  integrity sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==
 | 
			
		||||
  version "1.14.8"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
 | 
			
		||||
  integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
 | 
			
		||||
 | 
			
		||||
follow-redirects@^1.12.1:
 | 
			
		||||
  version "1.14.9"
 | 
			
		||||
@@ -13295,9 +13295,9 @@ ws@^5.1.1:
 | 
			
		||||
    async-limiter "~1.0.0"
 | 
			
		||||
 | 
			
		||||
ws@^7.0.0:
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881"
 | 
			
		||||
  integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==
 | 
			
		||||
  version "7.5.7"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67"
 | 
			
		||||
  integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==
 | 
			
		||||
 | 
			
		||||
wsrun@^5.2.4:
 | 
			
		||||
  version "5.2.4"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user