Compare commits
	
		
			10 Commits
		
	
	
		
			@0x/contra
			...
			feat/as/sa
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f732d3eb9b | ||
| 
						 | 
					5c57efe8a8 | ||
| 
						 | 
					da240653f4 | ||
| 
						 | 
					22ec626870 | ||
| 
						 | 
					2f60eb1c79 | ||
| 
						 | 
					313420473a | ||
| 
						 | 
					89a9424ae1 | ||
| 
						 | 
					eabca7a2ee | ||
| 
						 | 
					a5912c293e | ||
| 
						 | 
					83cae575fa | 
@@ -1,148 +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 "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ApproximateBuys {
 | 
			
		||||
 | 
			
		||||
    /// @dev Information computing buy quotes for sources that do not have native
 | 
			
		||||
    ///      buy quote support.
 | 
			
		||||
    struct ApproximateBuyQuoteOpts {
 | 
			
		||||
        // Arbitrary maker token data to pass to `getSellQuoteCallback`.
 | 
			
		||||
        bytes makerTokenData;
 | 
			
		||||
        // Arbitrary taker token data to pass to `getSellQuoteCallback`.
 | 
			
		||||
        bytes takerTokenData;
 | 
			
		||||
        // Callback to retrieve a sell quote.
 | 
			
		||||
        function (bytes memory, bytes memory, uint256)
 | 
			
		||||
            internal
 | 
			
		||||
            view
 | 
			
		||||
            returns (uint256) getSellQuoteCallback;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint256 private constant ONE_HUNDED_PERCENT_BPS = 1e4;
 | 
			
		||||
    /// @dev Maximum approximate (positive) error rate when approximating a buy quote.
 | 
			
		||||
    uint256 private constant APPROXIMATE_BUY_TARGET_EPSILON_BPS = 0.0005e4;
 | 
			
		||||
    /// @dev Maximum iterations to perform when approximating a buy quote.
 | 
			
		||||
    uint256 private constant APPROXIMATE_BUY_MAX_ITERATIONS = 5;
 | 
			
		||||
 | 
			
		||||
    function _sampleApproximateBuys(
 | 
			
		||||
        ApproximateBuyQuoteOpts memory opts,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        takerTokenAmounts = new uint256[](makerTokenAmounts.length);
 | 
			
		||||
        if (makerTokenAmounts.length == 0) {
 | 
			
		||||
            return takerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint256 sellAmount = opts.getSellQuoteCallback(
 | 
			
		||||
            opts.makerTokenData,
 | 
			
		||||
            opts.takerTokenData,
 | 
			
		||||
            makerTokenAmounts[0]
 | 
			
		||||
        );
 | 
			
		||||
        if (sellAmount == 0) {
 | 
			
		||||
            return takerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint256 buyAmount = opts.getSellQuoteCallback(
 | 
			
		||||
            opts.takerTokenData,
 | 
			
		||||
            opts.makerTokenData,
 | 
			
		||||
            sellAmount
 | 
			
		||||
        );
 | 
			
		||||
        if (buyAmount == 0) {
 | 
			
		||||
            return takerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < makerTokenAmounts.length; i++) {
 | 
			
		||||
            uint256 eps = 0;
 | 
			
		||||
            for (uint256 iter = 0; iter < APPROXIMATE_BUY_MAX_ITERATIONS; iter++) {
 | 
			
		||||
                // adjustedSellAmount = previousSellAmount * (target/actual) * JUMP_MULTIPLIER
 | 
			
		||||
                sellAmount = _safeGetPartialAmountCeil(
 | 
			
		||||
                    makerTokenAmounts[i],
 | 
			
		||||
                    buyAmount,
 | 
			
		||||
                    sellAmount
 | 
			
		||||
                );
 | 
			
		||||
                if (sellAmount == 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                sellAmount = _safeGetPartialAmountCeil(
 | 
			
		||||
                    (ONE_HUNDED_PERCENT_BPS + APPROXIMATE_BUY_TARGET_EPSILON_BPS),
 | 
			
		||||
                    ONE_HUNDED_PERCENT_BPS,
 | 
			
		||||
                    sellAmount
 | 
			
		||||
                );
 | 
			
		||||
                if (sellAmount == 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                uint256 _buyAmount = opts.getSellQuoteCallback(
 | 
			
		||||
                    opts.takerTokenData,
 | 
			
		||||
                    opts.makerTokenData,
 | 
			
		||||
                    sellAmount
 | 
			
		||||
                );
 | 
			
		||||
                if (_buyAmount == 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                // We re-use buyAmount next iteration, only assign if it is
 | 
			
		||||
                // non zero
 | 
			
		||||
                buyAmount = _buyAmount;
 | 
			
		||||
                // If we've reached our goal, exit early
 | 
			
		||||
                if (buyAmount >= makerTokenAmounts[i]) {
 | 
			
		||||
                    eps =
 | 
			
		||||
                        (buyAmount - makerTokenAmounts[i]) * ONE_HUNDED_PERCENT_BPS /
 | 
			
		||||
                        makerTokenAmounts[i];
 | 
			
		||||
                    if (eps <= APPROXIMATE_BUY_TARGET_EPSILON_BPS) {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (eps == 0 || eps > APPROXIMATE_BUY_TARGET_EPSILON_BPS) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            // We do our best to close in on the requested amount, but we can either over buy or under buy and exit
 | 
			
		||||
            // if we hit a max iteration limit
 | 
			
		||||
            // We scale the sell amount to get the approximate target
 | 
			
		||||
            takerTokenAmounts[i] = _safeGetPartialAmountCeil(
 | 
			
		||||
                makerTokenAmounts[i],
 | 
			
		||||
                buyAmount,
 | 
			
		||||
                sellAmount
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _safeGetPartialAmountCeil(
 | 
			
		||||
        uint256 numerator,
 | 
			
		||||
        uint256 denominator,
 | 
			
		||||
        uint256 target
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 partialAmount)
 | 
			
		||||
    {
 | 
			
		||||
        if (numerator == 0 || target == 0 || denominator == 0) return 0;
 | 
			
		||||
        uint256 c = numerator * target;
 | 
			
		||||
        if (c / numerator != target) return 0;
 | 
			
		||||
        return (c + (denominator - 1)) / denominator;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,197 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./interfaces/IBalancer.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract BalancerSampler {
 | 
			
		||||
 | 
			
		||||
    /// @dev Base gas limit for Balancer calls.
 | 
			
		||||
    uint256 constant private BALANCER_CALL_GAS = 300e3; // 300k
 | 
			
		||||
 | 
			
		||||
    // Balancer math constants
 | 
			
		||||
    // https://github.com/balancer-labs/balancer-core/blob/master/contracts/BConst.sol
 | 
			
		||||
    uint256 constant private BONE = 10 ** 18;
 | 
			
		||||
    uint256 constant private MAX_IN_RATIO = BONE / 2;
 | 
			
		||||
    uint256 constant private MAX_OUT_RATIO = (BONE / 3) + 1 wei;
 | 
			
		||||
 | 
			
		||||
    struct BalancerState {
 | 
			
		||||
        uint256 takerTokenBalance;
 | 
			
		||||
        uint256 makerTokenBalance;
 | 
			
		||||
        uint256 takerTokenWeight;
 | 
			
		||||
        uint256 makerTokenWeight;
 | 
			
		||||
        uint256 swapFee;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from Balancer.
 | 
			
		||||
    /// @param poolAddress Address of the Balancer pool to query.
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromBalancer(
 | 
			
		||||
        address poolAddress,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        IBalancer pool = IBalancer(poolAddress);
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        if (!pool.isBound(takerToken) || !pool.isBound(makerToken)) {
 | 
			
		||||
            return makerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        BalancerState memory poolState;
 | 
			
		||||
        poolState.takerTokenBalance = pool.getBalance(takerToken);
 | 
			
		||||
        poolState.makerTokenBalance = pool.getBalance(makerToken);
 | 
			
		||||
        poolState.takerTokenWeight = pool.getDenormalizedWeight(takerToken);
 | 
			
		||||
        poolState.makerTokenWeight = pool.getDenormalizedWeight(makerToken);
 | 
			
		||||
        poolState.swapFee = pool.getSwapFee();
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            // Handles this revert scenario:
 | 
			
		||||
            // https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol#L443
 | 
			
		||||
            if (takerTokenAmounts[i] > _bmul(poolState.takerTokenBalance, MAX_IN_RATIO)) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            try
 | 
			
		||||
                pool.calcOutGivenIn
 | 
			
		||||
                    {gas: BALANCER_CALL_GAS}
 | 
			
		||||
                    (
 | 
			
		||||
                        poolState.takerTokenBalance,
 | 
			
		||||
                        poolState.takerTokenWeight,
 | 
			
		||||
                        poolState.makerTokenBalance,
 | 
			
		||||
                        poolState.makerTokenWeight,
 | 
			
		||||
                        takerTokenAmounts[i],
 | 
			
		||||
                        poolState.swapFee
 | 
			
		||||
                    )
 | 
			
		||||
                returns (uint256 amount)
 | 
			
		||||
            {
 | 
			
		||||
                makerTokenAmounts[i] = amount;
 | 
			
		||||
                // Break early if there are 0 amounts
 | 
			
		||||
                if (makerTokenAmounts[i] == 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from Balancer.
 | 
			
		||||
    /// @param poolAddress Address of the Balancer pool to query.
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromBalancer(
 | 
			
		||||
        address poolAddress,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        IBalancer pool = IBalancer(poolAddress);
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        if (!pool.isBound(takerToken) || !pool.isBound(makerToken)) {
 | 
			
		||||
            return takerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        BalancerState memory poolState;
 | 
			
		||||
        poolState.takerTokenBalance = pool.getBalance(takerToken);
 | 
			
		||||
        poolState.makerTokenBalance = pool.getBalance(makerToken);
 | 
			
		||||
        poolState.takerTokenWeight = pool.getDenormalizedWeight(takerToken);
 | 
			
		||||
        poolState.makerTokenWeight = pool.getDenormalizedWeight(makerToken);
 | 
			
		||||
        poolState.swapFee = pool.getSwapFee();
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            // Handles this revert scenario:
 | 
			
		||||
            // https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol#L505
 | 
			
		||||
            if (makerTokenAmounts[i] > _bmul(poolState.makerTokenBalance, MAX_OUT_RATIO)) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            try
 | 
			
		||||
                pool.calcInGivenOut
 | 
			
		||||
                    {gas: BALANCER_CALL_GAS}
 | 
			
		||||
                    (
 | 
			
		||||
                        poolState.takerTokenBalance,
 | 
			
		||||
                        poolState.takerTokenWeight,
 | 
			
		||||
                        poolState.makerTokenBalance,
 | 
			
		||||
                        poolState.makerTokenWeight,
 | 
			
		||||
                        makerTokenAmounts[i],
 | 
			
		||||
                        poolState.swapFee
 | 
			
		||||
                    )
 | 
			
		||||
                returns (uint256 amount)
 | 
			
		||||
            {
 | 
			
		||||
                // Handles this revert scenario:
 | 
			
		||||
                // https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol#L443
 | 
			
		||||
                if (amount > _bmul(poolState.takerTokenBalance, MAX_IN_RATIO)) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                takerTokenAmounts[i] = amount;
 | 
			
		||||
                // Break early if there are 0 amounts
 | 
			
		||||
                if (takerTokenAmounts[i] == 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Hacked version of Balancer's `bmul` function, returning 0 instead
 | 
			
		||||
    ///      of reverting.
 | 
			
		||||
    ///      https://github.com/balancer-labs/balancer-core/blob/master/contracts/BNum.sol#L63-L73
 | 
			
		||||
    /// @param a The first operand.
 | 
			
		||||
    /// @param b The second operand.
 | 
			
		||||
    /// @param c The result of the multiplication, or 0 if `bmul` would've reverted.
 | 
			
		||||
    function _bmul(uint256 a, uint256 b)
 | 
			
		||||
        private
 | 
			
		||||
        pure
 | 
			
		||||
        returns (uint256 c)
 | 
			
		||||
    {
 | 
			
		||||
        uint c0 = a * b;
 | 
			
		||||
        if (a != 0 && c0 / a != b) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        uint c1 = c0 + (BONE / 2);
 | 
			
		||||
        if (c1 < c0) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        uint c2 = c1 / BONE;
 | 
			
		||||
        return c2;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,189 +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";
 | 
			
		||||
 | 
			
		||||
/// @dev Minimal Balancer V2 Vault interface
 | 
			
		||||
///      for documentation refer to https://github.com/balancer-labs/balancer-core-v2/blob/master/contracts/vault/interfaces/IVault.sol
 | 
			
		||||
interface IBalancerV2Vault {
 | 
			
		||||
    enum SwapKind { GIVEN_IN, GIVEN_OUT }
 | 
			
		||||
 | 
			
		||||
    struct BatchSwapStep {
 | 
			
		||||
        bytes32 poolId;
 | 
			
		||||
        uint256 assetInIndex;
 | 
			
		||||
        uint256 assetOutIndex;
 | 
			
		||||
        uint256 amount;
 | 
			
		||||
        bytes userData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct FundManagement {
 | 
			
		||||
        address sender;
 | 
			
		||||
        bool fromInternalBalance;
 | 
			
		||||
        address payable recipient;
 | 
			
		||||
        bool toInternalBalance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function queryBatchSwap(
 | 
			
		||||
        SwapKind kind,
 | 
			
		||||
        BatchSwapStep[] calldata swaps,
 | 
			
		||||
        IAsset[] calldata assets,
 | 
			
		||||
        FundManagement calldata funds
 | 
			
		||||
    ) external returns (int256[] memory assetDeltas);
 | 
			
		||||
}
 | 
			
		||||
interface IAsset {
 | 
			
		||||
    // solhint-disable-previous-line no-empty-blocks
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract BalancerV2Sampler is SamplerUtils {
 | 
			
		||||
 | 
			
		||||
    struct BalancerV2PoolInfo {
 | 
			
		||||
        bytes32 poolId;
 | 
			
		||||
        address vault;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from Balancer V2.
 | 
			
		||||
    /// @param poolInfo Struct with pool related data
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromBalancerV2(
 | 
			
		||||
        BalancerV2PoolInfo memory poolInfo,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
 | 
			
		||||
        IAsset[] memory swapAssets = new IAsset[](2);
 | 
			
		||||
        swapAssets[0] = IAsset(takerToken);
 | 
			
		||||
        swapAssets[1] = IAsset(makerToken);
 | 
			
		||||
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        IBalancerV2Vault.FundManagement memory swapFunds =
 | 
			
		||||
            _createSwapFunds();
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
 | 
			
		||||
                _createSwapSteps(poolInfo, takerTokenAmounts[i]);
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
                // For sells we specify the takerToken which is what the vault will receive from the trade
 | 
			
		||||
                vault.queryBatchSwap(IBalancerV2Vault.SwapKind.GIVEN_IN, swapSteps, swapAssets, swapFunds)
 | 
			
		||||
            // amounts represent pool balance deltas from the swap (incoming balance, outgoing balance)
 | 
			
		||||
            returns (int256[] memory amounts) {
 | 
			
		||||
                // Outgoing balance is negative so we need to flip the sign
 | 
			
		||||
                int256 amountOutFromPool = amounts[1] * -1;
 | 
			
		||||
                if (amountOutFromPool <= 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                makerTokenAmounts[i] = uint256(amountOutFromPool);
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from Balancer V2.
 | 
			
		||||
    /// @param poolInfo Struct with pool related data
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromBalancerV2(
 | 
			
		||||
        BalancerV2PoolInfo memory poolInfo,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault);
 | 
			
		||||
        IAsset[] memory swapAssets = new IAsset[](2);
 | 
			
		||||
        swapAssets[0] = IAsset(takerToken);
 | 
			
		||||
        swapAssets[1] = IAsset(makerToken);
 | 
			
		||||
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        IBalancerV2Vault.FundManagement memory swapFunds =
 | 
			
		||||
            _createSwapFunds();
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
 | 
			
		||||
                _createSwapSteps(poolInfo, makerTokenAmounts[i]);
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
                // For buys we specify the makerToken which is what taker will receive from the trade
 | 
			
		||||
                vault.queryBatchSwap(IBalancerV2Vault.SwapKind.GIVEN_OUT, swapSteps, swapAssets, swapFunds)
 | 
			
		||||
            returns (int256[] memory amounts) {
 | 
			
		||||
                int256 amountIntoPool = amounts[0];
 | 
			
		||||
                if (amountIntoPool <= 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                takerTokenAmounts[i] = uint256(amountIntoPool);
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _createSwapSteps(
 | 
			
		||||
        BalancerV2PoolInfo memory poolInfo,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    ) private pure returns (IBalancerV2Vault.BatchSwapStep[] memory) {
 | 
			
		||||
        IBalancerV2Vault.BatchSwapStep[] memory swapSteps =
 | 
			
		||||
            new IBalancerV2Vault.BatchSwapStep[](1);
 | 
			
		||||
        swapSteps[0] = IBalancerV2Vault.BatchSwapStep({
 | 
			
		||||
            poolId: poolInfo.poolId,
 | 
			
		||||
            assetInIndex: 0,
 | 
			
		||||
            assetOutIndex: 1,
 | 
			
		||||
            amount: amount,
 | 
			
		||||
            userData: ""
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return swapSteps;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _createSwapFunds()
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (IBalancerV2Vault.FundManagement memory)
 | 
			
		||||
    {
 | 
			
		||||
        return
 | 
			
		||||
            IBalancerV2Vault.FundManagement({
 | 
			
		||||
                sender: address(this),
 | 
			
		||||
                fromInternalBalance: false,
 | 
			
		||||
                recipient: payable(address(this)),
 | 
			
		||||
                toInternalBalance: false
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,142 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./interfaces/IBancor.sol";
 | 
			
		||||
 | 
			
		||||
contract CompilerHack {}
 | 
			
		||||
 | 
			
		||||
contract BancorSampler is CompilerHack {
 | 
			
		||||
 | 
			
		||||
    /// @dev Base gas limit for Bancor calls.
 | 
			
		||||
    uint256 constant private BANCOR_CALL_GAS = 300e3; // 300k
 | 
			
		||||
 | 
			
		||||
    struct BancorSamplerOpts {
 | 
			
		||||
        IBancorRegistry registry;
 | 
			
		||||
        address[][] paths;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from Bancor.
 | 
			
		||||
    /// @param opts BancorSamplerOpts The Bancor registry contract address and paths
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return bancorNetwork the Bancor Network address
 | 
			
		||||
    /// @return path the selected conversion path from bancor
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromBancor(
 | 
			
		||||
        BancorSamplerOpts memory opts,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (address bancorNetwork, address[] memory path, uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        if (opts.paths.length == 0) {
 | 
			
		||||
            return (bancorNetwork, path, makerTokenAmounts);
 | 
			
		||||
        }
 | 
			
		||||
        (bancorNetwork, path) = _findBestPath(opts, takerToken, makerToken, takerTokenAmounts);
 | 
			
		||||
        makerTokenAmounts = new uint256[](takerTokenAmounts.length);
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < makerTokenAmounts.length; i++) {
 | 
			
		||||
            try
 | 
			
		||||
                IBancorNetwork(bancorNetwork)
 | 
			
		||||
                    .rateByPath
 | 
			
		||||
                        {gas: BANCOR_CALL_GAS}
 | 
			
		||||
                        (path, takerTokenAmounts[i])
 | 
			
		||||
                returns (uint256 amount)
 | 
			
		||||
            {
 | 
			
		||||
                makerTokenAmounts[i] = amount;
 | 
			
		||||
                // Break early if there are 0 amounts
 | 
			
		||||
                if (makerTokenAmounts[i] == 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            } catch {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return (bancorNetwork, path, makerTokenAmounts);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from Bancor. Unimplemented
 | 
			
		||||
    /// @param opts BancorSamplerOpts The Bancor registry contract address and paths
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return bancorNetwork the Bancor Network address
 | 
			
		||||
    /// @return path the selected conversion path from bancor
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromBancor(
 | 
			
		||||
        BancorSamplerOpts memory opts,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (address bancorNetwork, address[] memory path, uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _findBestPath(
 | 
			
		||||
        BancorSamplerOpts memory opts,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address bancorNetwork, address[] memory path)
 | 
			
		||||
    {
 | 
			
		||||
        bancorNetwork = opts.registry.getAddress(opts.registry.BANCOR_NETWORK());
 | 
			
		||||
        if (opts.paths.length == 0) {
 | 
			
		||||
            return (bancorNetwork, path);
 | 
			
		||||
        }
 | 
			
		||||
        uint256 maxBoughtAmount = 0;
 | 
			
		||||
        // Find the best path by selling the largest taker amount
 | 
			
		||||
        for (uint256 i = 0; i < opts.paths.length; i++) {
 | 
			
		||||
            if (opts.paths[i].length < 2) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
                IBancorNetwork(bancorNetwork)
 | 
			
		||||
                    .rateByPath
 | 
			
		||||
                        {gas: BANCOR_CALL_GAS}
 | 
			
		||||
                        (opts.paths[i], takerTokenAmounts[takerTokenAmounts.length-1])
 | 
			
		||||
                returns (uint256 amount)
 | 
			
		||||
            {
 | 
			
		||||
                if (amount > maxBoughtAmount) {
 | 
			
		||||
                    maxBoughtAmount = amount;
 | 
			
		||||
                    path = opts.paths[i];
 | 
			
		||||
                }
 | 
			
		||||
            } catch {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,161 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./interfaces/ICurve.sol";
 | 
			
		||||
import "./ApproximateBuys.sol";
 | 
			
		||||
import "./SamplerUtils.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract CurveSampler is
 | 
			
		||||
    SamplerUtils,
 | 
			
		||||
    ApproximateBuys
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Information for sampling from curve sources.
 | 
			
		||||
    struct CurveInfo {
 | 
			
		||||
        address poolAddress;
 | 
			
		||||
        bytes4 sellQuoteFunctionSelector;
 | 
			
		||||
        bytes4 buyQuoteFunctionSelector;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Base gas limit for Curve calls. Some Curves have multiple tokens
 | 
			
		||||
    ///      So a reasonable ceil is 150k per token. Biggest Curve has 4 tokens.
 | 
			
		||||
    uint256 constant private CURVE_CALL_GAS = 2000e3; // Was 600k for Curve but SnowSwap is using 1500k+
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from Curve.
 | 
			
		||||
    /// @param curveInfo Curve information specific to this token pair.
 | 
			
		||||
    /// @param fromTokenIdx Index of the taker token (what to sell).
 | 
			
		||||
    /// @param toTokenIdx Index of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromCurve(
 | 
			
		||||
        CurveInfo memory curveInfo,
 | 
			
		||||
        int128 fromTokenIdx,
 | 
			
		||||
        int128 toTokenIdx,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            (bool didSucceed, bytes memory resultData) =
 | 
			
		||||
                curveInfo.poolAddress.staticcall.gas(CURVE_CALL_GAS)(
 | 
			
		||||
                    abi.encodeWithSelector(
 | 
			
		||||
                        curveInfo.sellQuoteFunctionSelector,
 | 
			
		||||
                        fromTokenIdx,
 | 
			
		||||
                        toTokenIdx,
 | 
			
		||||
                        takerTokenAmounts[i]
 | 
			
		||||
                    ));
 | 
			
		||||
            uint256 buyAmount = 0;
 | 
			
		||||
            if (didSucceed) {
 | 
			
		||||
                buyAmount = abi.decode(resultData, (uint256));
 | 
			
		||||
            }
 | 
			
		||||
            makerTokenAmounts[i] = buyAmount;
 | 
			
		||||
            // Break early if there are 0 amounts
 | 
			
		||||
            if (makerTokenAmounts[i] == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from Curve.
 | 
			
		||||
    /// @param curveInfo Curve information specific to this token pair.
 | 
			
		||||
    /// @param fromTokenIdx Index of the taker token (what to sell).
 | 
			
		||||
    /// @param toTokenIdx Index of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromCurve(
 | 
			
		||||
        CurveInfo memory curveInfo,
 | 
			
		||||
        int128 fromTokenIdx,
 | 
			
		||||
        int128 toTokenIdx,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        if (curveInfo.buyQuoteFunctionSelector == bytes4(0)) {
 | 
			
		||||
            // Buys not supported on this curve, so approximate it.
 | 
			
		||||
            return _sampleApproximateBuys(
 | 
			
		||||
                ApproximateBuyQuoteOpts({
 | 
			
		||||
                    makerTokenData: abi.encode(toTokenIdx, curveInfo),
 | 
			
		||||
                    takerTokenData: abi.encode(fromTokenIdx, curveInfo),
 | 
			
		||||
                    getSellQuoteCallback: _sampleSellForApproximateBuyFromCurve
 | 
			
		||||
                }),
 | 
			
		||||
                makerTokenAmounts
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            (bool didSucceed, bytes memory resultData) =
 | 
			
		||||
                curveInfo.poolAddress.staticcall.gas(CURVE_CALL_GAS)(
 | 
			
		||||
                    abi.encodeWithSelector(
 | 
			
		||||
                        curveInfo.buyQuoteFunctionSelector,
 | 
			
		||||
                        fromTokenIdx,
 | 
			
		||||
                        toTokenIdx,
 | 
			
		||||
                        makerTokenAmounts[i]
 | 
			
		||||
                    ));
 | 
			
		||||
            uint256 sellAmount = 0;
 | 
			
		||||
            if (didSucceed) {
 | 
			
		||||
                sellAmount = abi.decode(resultData, (uint256));
 | 
			
		||||
            }
 | 
			
		||||
            takerTokenAmounts[i] = sellAmount;
 | 
			
		||||
            // Break early if there are 0 amounts
 | 
			
		||||
            if (takerTokenAmounts[i] == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sampleSellForApproximateBuyFromCurve(
 | 
			
		||||
        bytes memory takerTokenData,
 | 
			
		||||
        bytes memory makerTokenData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        (int128 takerTokenIdx, CurveInfo memory curveInfo) =
 | 
			
		||||
            abi.decode(takerTokenData, (int128, CurveInfo));
 | 
			
		||||
        (int128 makerTokenIdx) =
 | 
			
		||||
            abi.decode(makerTokenData, (int128));
 | 
			
		||||
        (bool success, bytes memory resultData) =
 | 
			
		||||
            address(this).staticcall(abi.encodeWithSelector(
 | 
			
		||||
                this.sampleSellsFromCurve.selector,
 | 
			
		||||
                curveInfo,
 | 
			
		||||
                takerTokenIdx,
 | 
			
		||||
                makerTokenIdx,
 | 
			
		||||
                _toSingleValueArray(sellAmount)
 | 
			
		||||
            ));
 | 
			
		||||
        if (!success) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        // solhint-disable-next-line indent
 | 
			
		||||
        return abi.decode(resultData, (uint256[]))[0];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,211 +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 "./ApproximateBuys.sol";
 | 
			
		||||
import "./SamplerUtils.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IDODOZoo {
 | 
			
		||||
    function getDODO(address baseToken, address quoteToken) external view returns (address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IDODOHelper {
 | 
			
		||||
    function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IDODO {
 | 
			
		||||
    function querySellBaseToken(uint256 amount) external view returns (uint256);
 | 
			
		||||
    function _TRADE_ALLOWED_() external view returns (bool);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract DODOSampler is
 | 
			
		||||
    SamplerUtils,
 | 
			
		||||
    ApproximateBuys
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// @dev Gas limit for DODO calls.
 | 
			
		||||
    uint256 constant private DODO_CALL_GAS = 300e3; // 300k
 | 
			
		||||
    struct DODOSamplerOpts {
 | 
			
		||||
        address registry;
 | 
			
		||||
        address helper;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from DODO.
 | 
			
		||||
    /// @param opts DODOSamplerOpts DODO Registry and helper addresses
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return sellBase whether the bridge needs to sell the base token
 | 
			
		||||
    /// @return pool the DODO pool address
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromDODO(
 | 
			
		||||
        DODOSamplerOpts memory opts,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (bool sellBase, address pool, uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        pool = IDODOZoo(opts.registry).getDODO(takerToken, makerToken);
 | 
			
		||||
        address baseToken;
 | 
			
		||||
        // If pool exists we have the correct order of Base/Quote
 | 
			
		||||
        if (pool != address(0)) {
 | 
			
		||||
            baseToken = takerToken;
 | 
			
		||||
            sellBase = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            pool = IDODOZoo(opts.registry).getDODO(makerToken, takerToken);
 | 
			
		||||
            // No pool either direction
 | 
			
		||||
            if (address(pool) == address(0)) {
 | 
			
		||||
                return (sellBase, pool, makerTokenAmounts);
 | 
			
		||||
            }
 | 
			
		||||
            baseToken = makerToken;
 | 
			
		||||
            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, opts.helper), // taker token data
 | 
			
		||||
                abi.encode(makerToken, pool, baseToken, opts.helper), // maker token data
 | 
			
		||||
                takerTokenAmounts[i]
 | 
			
		||||
            );
 | 
			
		||||
            makerTokenAmounts[i] = buyAmount;
 | 
			
		||||
            // Break early if there are 0 amounts
 | 
			
		||||
            if (makerTokenAmounts[i] == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from DODO.
 | 
			
		||||
    /// @param opts DODOSamplerOpts DODO Registry and helper addresses
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token sell amount for each sample.
 | 
			
		||||
    /// @return sellBase whether the bridge needs to sell the base token
 | 
			
		||||
    /// @return pool the DODO pool address
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromDODO(
 | 
			
		||||
        DODOSamplerOpts memory opts,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (bool sellBase, address pool, uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        // Pool is BASE/QUOTE
 | 
			
		||||
        // Look up the pool from the taker/maker combination
 | 
			
		||||
        pool = IDODOZoo(opts.registry).getDODO(takerToken, makerToken);
 | 
			
		||||
        address baseToken;
 | 
			
		||||
        // If pool exists we have the correct order of Base/Quote
 | 
			
		||||
        if (pool != address(0)) {
 | 
			
		||||
            baseToken = takerToken;
 | 
			
		||||
            sellBase = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Look up the pool from the maker/taker combination
 | 
			
		||||
            pool = IDODOZoo(opts.registry).getDODO(makerToken, takerToken);
 | 
			
		||||
            // No pool either direction
 | 
			
		||||
            if (address(pool) == address(0)) {
 | 
			
		||||
                return (sellBase, pool, takerTokenAmounts);
 | 
			
		||||
            }
 | 
			
		||||
            baseToken = makerToken;
 | 
			
		||||
            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, opts.helper),
 | 
			
		||||
                takerTokenData: abi.encode(takerToken, pool, baseToken, opts.helper),
 | 
			
		||||
                getSellQuoteCallback: _sampleSellForApproximateBuyFromDODO
 | 
			
		||||
            }),
 | 
			
		||||
            makerTokenAmounts
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sampleSellForApproximateBuyFromDODO(
 | 
			
		||||
        bytes memory takerTokenData,
 | 
			
		||||
        bytes memory /* makerTokenData */,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        (address takerToken, address pool, address baseToken, address helper) = abi.decode(
 | 
			
		||||
            takerTokenData,
 | 
			
		||||
            (address, address, address, address)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // We will get called to sell both the taker token and also to sell the maker token
 | 
			
		||||
        if (takerToken == baseToken) {
 | 
			
		||||
            // If base token then use the original query on the pool
 | 
			
		||||
            try
 | 
			
		||||
                IDODO(pool).querySellBaseToken
 | 
			
		||||
                    {gas: DODO_CALL_GAS}
 | 
			
		||||
                    (sellAmount)
 | 
			
		||||
                returns (uint256 amount)
 | 
			
		||||
            {
 | 
			
		||||
                return amount;
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // If quote token then use helper, this is less accurate
 | 
			
		||||
            try
 | 
			
		||||
                IDODOHelper(helper).querySellQuoteToken
 | 
			
		||||
                    {gas: DODO_CALL_GAS}
 | 
			
		||||
                    (pool, sellAmount)
 | 
			
		||||
                returns (uint256 amount)
 | 
			
		||||
            {
 | 
			
		||||
                return amount;
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,204 +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 "./ApproximateBuys.sol";
 | 
			
		||||
import "./SamplerUtils.sol";
 | 
			
		||||
 | 
			
		||||
interface IDODOV2Registry {
 | 
			
		||||
    function getDODOPool(address baseToken, address quoteToken)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address[] memory machines);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IDODOV2Pool {
 | 
			
		||||
    function querySellBase(address trader, uint256 payBaseAmount)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 receiveQuoteAmount, uint256 mtFee);
 | 
			
		||||
 | 
			
		||||
    function querySellQuote(address trader, uint256 payQuoteAmount)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 receiveBaseAmount, uint256 mtFee);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract DODOV2Sampler is
 | 
			
		||||
    SamplerUtils,
 | 
			
		||||
    ApproximateBuys
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// @dev Gas limit for DODO V2 calls.
 | 
			
		||||
    uint256 constant private DODO_V2_CALL_GAS = 300e3; // 300k
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from DODO V2.
 | 
			
		||||
    /// @param registry Address of the registry to look up.
 | 
			
		||||
    /// @param offset offset index for the pool in the registry.
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return sellBase whether the bridge needs to sell the base token
 | 
			
		||||
    /// @return pool the DODO pool address
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromDODOV2(
 | 
			
		||||
        address registry,
 | 
			
		||||
        uint256 offset,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (bool sellBase, address pool, uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        (pool, sellBase) = _getNextDODOV2Pool(registry, offset, takerToken, makerToken);
 | 
			
		||||
        if (pool == address(0)) {
 | 
			
		||||
            return (sellBase, pool, makerTokenAmounts);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            uint256 buyAmount = _sampleSellForApproximateBuyFromDODOV2(
 | 
			
		||||
                abi.encode(takerToken, pool, sellBase), // taker token data
 | 
			
		||||
                abi.encode(makerToken, pool, sellBase), // maker token data
 | 
			
		||||
                takerTokenAmounts[i]
 | 
			
		||||
            );
 | 
			
		||||
            makerTokenAmounts[i] = buyAmount;
 | 
			
		||||
            // Break early if there are 0 amounts
 | 
			
		||||
            if (makerTokenAmounts[i] == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from DODO.
 | 
			
		||||
    /// @param registry Address of the registry to look up.
 | 
			
		||||
    /// @param offset offset index for the pool in the registry.
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token sell amount for each sample.
 | 
			
		||||
    /// @return sellBase whether the bridge needs to sell the base token
 | 
			
		||||
    /// @return pool the DODO pool address
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromDODOV2(
 | 
			
		||||
        address registry,
 | 
			
		||||
        uint256 offset,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (bool sellBase, address pool, uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        (pool, sellBase) = _getNextDODOV2Pool(registry, offset, takerToken, makerToken);
 | 
			
		||||
        if (pool == address(0)) {
 | 
			
		||||
            return (sellBase, pool, takerTokenAmounts);
 | 
			
		||||
        }
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        takerTokenAmounts = _sampleApproximateBuys(
 | 
			
		||||
            ApproximateBuyQuoteOpts({
 | 
			
		||||
                makerTokenData: abi.encode(makerToken, pool, !sellBase),
 | 
			
		||||
                takerTokenData: abi.encode(takerToken, pool, sellBase),
 | 
			
		||||
                getSellQuoteCallback: _sampleSellForApproximateBuyFromDODOV2
 | 
			
		||||
            }),
 | 
			
		||||
            makerTokenAmounts
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sampleSellForApproximateBuyFromDODOV2(
 | 
			
		||||
        bytes memory takerTokenData,
 | 
			
		||||
        bytes memory /* makerTokenData */,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        (address takerToken, address pool, bool sellBase) = abi.decode(
 | 
			
		||||
            takerTokenData,
 | 
			
		||||
            (address, address, bool)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // We will get called to sell both the taker token and also to sell the maker token
 | 
			
		||||
        // since we use approximate buy for sell and buy functions
 | 
			
		||||
        if (sellBase) {
 | 
			
		||||
            try
 | 
			
		||||
                IDODOV2Pool(pool).querySellBase
 | 
			
		||||
                    { gas: DODO_V2_CALL_GAS }
 | 
			
		||||
                    (address(0), sellAmount)
 | 
			
		||||
                returns (uint256 amount, uint256)
 | 
			
		||||
            {
 | 
			
		||||
                return amount;
 | 
			
		||||
            } catch {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            try
 | 
			
		||||
                IDODOV2Pool(pool).querySellQuote
 | 
			
		||||
                    { gas: DODO_V2_CALL_GAS }
 | 
			
		||||
                    (address(0), sellAmount)
 | 
			
		||||
                returns (uint256 amount, uint256)
 | 
			
		||||
            {
 | 
			
		||||
                return amount;
 | 
			
		||||
            } catch {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _getNextDODOV2Pool(
 | 
			
		||||
        address registry,
 | 
			
		||||
        uint256 offset,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address machine, bool sellBase)
 | 
			
		||||
    {
 | 
			
		||||
        // Query in base -> quote direction, if a pool is found then we are selling the base
 | 
			
		||||
        address[] memory machines = IDODOV2Registry(registry).getDODOPool(takerToken, makerToken);
 | 
			
		||||
        sellBase = true;
 | 
			
		||||
        if (machines.length == 0) {
 | 
			
		||||
            // Query in quote -> base direction, if a pool is found then we are selling the quote
 | 
			
		||||
            machines = IDODOV2Registry(registry).getDODOPool(makerToken, takerToken);
 | 
			
		||||
            sellBase = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (offset >= machines.length) {
 | 
			
		||||
            return (address(0), false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        machine = machines[offset];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,93 +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 "./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,
 | 
			
		||||
    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,176 +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)
 | 
			
		||||
            {
 | 
			
		||||
                uint256 maxSupply = 0;
 | 
			
		||||
                require(allPools.length >= 1, "KyberDMMSampler/NO_POOLS_FOUND");
 | 
			
		||||
                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,301 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./interfaces/IKyberNetwork.sol";
 | 
			
		||||
import "./ApproximateBuys.sol";
 | 
			
		||||
import "./SamplerUtils.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract KyberSampler is
 | 
			
		||||
    SamplerUtils,
 | 
			
		||||
    ApproximateBuys
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Gas limit for Kyber calls.
 | 
			
		||||
    uint256 constant private KYBER_CALL_GAS = 500e3; // 500k
 | 
			
		||||
    /// @dev Kyber ETH pseudo-address.
 | 
			
		||||
    address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
 | 
			
		||||
 | 
			
		||||
    struct KyberSamplerOpts {
 | 
			
		||||
        uint256 reserveOffset;
 | 
			
		||||
        address hintHandler;
 | 
			
		||||
        address networkProxy;
 | 
			
		||||
        address weth;
 | 
			
		||||
        bytes hint;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from Kyber.
 | 
			
		||||
    /// @param opts KyberSamplerOpts The nth reserve
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return reserveId The id of the reserve found at reserveOffset
 | 
			
		||||
    /// @return hint The hint for the selected reserve
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token amount.
 | 
			
		||||
    function sampleSellsFromKyberNetwork(
 | 
			
		||||
        KyberSamplerOpts memory opts,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes32 reserveId, bytes memory hint, uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        reserveId = _getNextReserveId(opts, takerToken, makerToken);
 | 
			
		||||
        if (reserveId == 0x0) {
 | 
			
		||||
            return (reserveId, hint, makerTokenAmounts);
 | 
			
		||||
        }
 | 
			
		||||
        opts.hint = this.encodeKyberHint(opts, reserveId, takerToken, makerToken);
 | 
			
		||||
        hint = opts.hint;
 | 
			
		||||
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            uint256 value = this.sampleSellFromKyberNetwork(
 | 
			
		||||
                opts,
 | 
			
		||||
                takerToken,
 | 
			
		||||
                makerToken,
 | 
			
		||||
                takerTokenAmounts[i]
 | 
			
		||||
            );
 | 
			
		||||
            makerTokenAmounts[i] = value;
 | 
			
		||||
            // Break early if there are 0 amounts
 | 
			
		||||
            if (makerTokenAmounts[i] == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from Kyber.
 | 
			
		||||
    /// @param opts KyberSamplerOpts The nth reserve
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return reserveId The id of the reserve found at reserveOffset
 | 
			
		||||
    /// @return hint The hint for the selected reserve
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token amount.
 | 
			
		||||
    function sampleBuysFromKyberNetwork(
 | 
			
		||||
        KyberSamplerOpts memory opts,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes32 reserveId, bytes memory hint, uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
 | 
			
		||||
        reserveId = _getNextReserveId(opts, takerToken, makerToken);
 | 
			
		||||
        if (reserveId == 0x0) {
 | 
			
		||||
            return (reserveId, hint, takerTokenAmounts);
 | 
			
		||||
        }
 | 
			
		||||
        opts.hint = this.encodeKyberHint(opts, reserveId, takerToken, makerToken);
 | 
			
		||||
        hint = opts.hint;
 | 
			
		||||
 | 
			
		||||
        takerTokenAmounts = _sampleApproximateBuys(
 | 
			
		||||
            ApproximateBuyQuoteOpts({
 | 
			
		||||
                makerTokenData: abi.encode(makerToken, opts),
 | 
			
		||||
                takerTokenData: abi.encode(takerToken, opts),
 | 
			
		||||
                getSellQuoteCallback: _sampleSellForApproximateBuyFromKyber
 | 
			
		||||
            }),
 | 
			
		||||
            makerTokenAmounts
 | 
			
		||||
        );
 | 
			
		||||
        return (reserveId, hint, takerTokenAmounts);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function encodeKyberHint(
 | 
			
		||||
        KyberSamplerOpts memory opts,
 | 
			
		||||
        bytes32 reserveId,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes memory hint)
 | 
			
		||||
    {
 | 
			
		||||
        // Build a hint selecting the single reserve
 | 
			
		||||
        IKyberHintHandler kyberHint = IKyberHintHandler(opts.hintHandler);
 | 
			
		||||
 | 
			
		||||
        // All other reserves should be ignored with this hint
 | 
			
		||||
        bytes32[] memory selectedReserves = new bytes32[](1);
 | 
			
		||||
        selectedReserves[0] = reserveId;
 | 
			
		||||
        uint256[] memory emptySplits = new uint256[](0);
 | 
			
		||||
 | 
			
		||||
        if (takerToken == opts.weth) {
 | 
			
		||||
            // ETH to Token
 | 
			
		||||
            try
 | 
			
		||||
                kyberHint.buildEthToTokenHint
 | 
			
		||||
                    {gas: KYBER_CALL_GAS}
 | 
			
		||||
                    (
 | 
			
		||||
                        makerToken,
 | 
			
		||||
                        IKyberHintHandler.TradeType.MaskIn,
 | 
			
		||||
                        selectedReserves,
 | 
			
		||||
                        emptySplits
 | 
			
		||||
                    )
 | 
			
		||||
                returns (bytes memory result)
 | 
			
		||||
            {
 | 
			
		||||
                return result;
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
            }
 | 
			
		||||
        } else if (makerToken == opts.weth) {
 | 
			
		||||
            // Token to ETH
 | 
			
		||||
            try
 | 
			
		||||
                kyberHint.buildTokenToEthHint
 | 
			
		||||
                    {gas: KYBER_CALL_GAS}
 | 
			
		||||
                    (
 | 
			
		||||
                        takerToken,
 | 
			
		||||
                        IKyberHintHandler.TradeType.MaskIn,
 | 
			
		||||
                        selectedReserves,
 | 
			
		||||
                        emptySplits
 | 
			
		||||
                    )
 | 
			
		||||
                returns (bytes memory result)
 | 
			
		||||
            {
 | 
			
		||||
                return result;
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
            // Token to Token
 | 
			
		||||
            // We use the same reserve both ways
 | 
			
		||||
            try
 | 
			
		||||
                kyberHint.buildTokenToTokenHint
 | 
			
		||||
                    {gas: KYBER_CALL_GAS}
 | 
			
		||||
                    (
 | 
			
		||||
                        takerToken,
 | 
			
		||||
                        IKyberHintHandler.TradeType.MaskIn,
 | 
			
		||||
                        selectedReserves,
 | 
			
		||||
                        emptySplits,
 | 
			
		||||
                        makerToken,
 | 
			
		||||
                        IKyberHintHandler.TradeType.MaskIn,
 | 
			
		||||
                        selectedReserves,
 | 
			
		||||
                        emptySplits
 | 
			
		||||
                    )
 | 
			
		||||
                returns (bytes memory result)
 | 
			
		||||
            {
 | 
			
		||||
                return result;
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sampleSellForApproximateBuyFromKyber(
 | 
			
		||||
        bytes memory takerTokenData,
 | 
			
		||||
        bytes memory makerTokenData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        (address makerToken, KyberSamplerOpts memory opts) =
 | 
			
		||||
            abi.decode(makerTokenData, (address, KyberSamplerOpts));
 | 
			
		||||
        (address takerToken, ) =
 | 
			
		||||
            abi.decode(takerTokenData, (address, KyberSamplerOpts));
 | 
			
		||||
        try
 | 
			
		||||
            this.sampleSellFromKyberNetwork
 | 
			
		||||
                (opts, takerToken, makerToken, sellAmount)
 | 
			
		||||
            returns (uint256 amount)
 | 
			
		||||
        {
 | 
			
		||||
            return amount;
 | 
			
		||||
        } catch (bytes memory) {
 | 
			
		||||
            // Swallow failures, leaving all results as zero.
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function sampleSellFromKyberNetwork(
 | 
			
		||||
        KyberSamplerOpts memory opts,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256 takerTokenAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 makerTokenAmount)
 | 
			
		||||
    {
 | 
			
		||||
        // If there is no hint do not continue
 | 
			
		||||
        if (opts.hint.length == 0) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
            IKyberNetworkProxy(opts.networkProxy).getExpectedRateAfterFee
 | 
			
		||||
                {gas: KYBER_CALL_GAS}
 | 
			
		||||
                (
 | 
			
		||||
                    takerToken == opts.weth ? KYBER_ETH_ADDRESS : takerToken,
 | 
			
		||||
                    makerToken == opts.weth ? KYBER_ETH_ADDRESS : makerToken,
 | 
			
		||||
                    takerTokenAmount,
 | 
			
		||||
                    0, // fee
 | 
			
		||||
                    opts.hint
 | 
			
		||||
                )
 | 
			
		||||
            returns (uint256 rate)
 | 
			
		||||
        {
 | 
			
		||||
            uint256 makerTokenDecimals = _getTokenDecimals(makerToken);
 | 
			
		||||
            uint256 takerTokenDecimals = _getTokenDecimals(takerToken);
 | 
			
		||||
            makerTokenAmount =
 | 
			
		||||
                rate *
 | 
			
		||||
                takerTokenAmount *
 | 
			
		||||
                10 ** makerTokenDecimals /
 | 
			
		||||
                10 ** takerTokenDecimals /
 | 
			
		||||
                10 ** 18;
 | 
			
		||||
            return makerTokenAmount;
 | 
			
		||||
        } catch (bytes memory) {
 | 
			
		||||
            // Swallow failures, leaving all results as zero.
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _getNextReserveId(
 | 
			
		||||
        KyberSamplerOpts memory opts,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes32 reserveId)
 | 
			
		||||
    {
 | 
			
		||||
        // Fetch the registered reserves for this pair
 | 
			
		||||
        IKyberHintHandler kyberHint = IKyberHintHandler(opts.hintHandler);
 | 
			
		||||
        (bytes32[] memory reserveIds, ,) = kyberHint.getTradingReserves(
 | 
			
		||||
            takerToken == opts.weth ? KYBER_ETH_ADDRESS : takerToken,
 | 
			
		||||
            makerToken == opts.weth ? KYBER_ETH_ADDRESS : makerToken,
 | 
			
		||||
            true,
 | 
			
		||||
            new bytes(0) // empty hint
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (opts.reserveOffset >= reserveIds.length) {
 | 
			
		||||
            return 0x0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        reserveId = reserveIds[opts.reserveOffset];
 | 
			
		||||
        // Ignore Kyber Bridged Reserves (0xbb)
 | 
			
		||||
        if (uint256(reserveId >> 248) == 0xbb) {
 | 
			
		||||
            return 0x0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return reserveId;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,91 +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";
 | 
			
		||||
 | 
			
		||||
contract LidoSampler is SamplerUtils {
 | 
			
		||||
    struct LidoInfo {
 | 
			
		||||
        address stEthToken;
 | 
			
		||||
        address wethToken;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from Lido
 | 
			
		||||
    /// @param lidoInfo Info regarding a specific Lido deployment
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromLido(
 | 
			
		||||
        LidoInfo memory lidoInfo,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (uint256[] memory)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
 | 
			
		||||
        if (takerToken != lidoInfo.wethToken || makerToken != address(lidoInfo.stEthToken)) {
 | 
			
		||||
            // Return 0 values if not selling WETH for stETH
 | 
			
		||||
            uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
            uint256[] memory makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
            return makerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Minting stETH is always 1:1 therefore we can just return the same amounts back
 | 
			
		||||
        return takerTokenAmounts;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from Lido.
 | 
			
		||||
    /// @param lidoInfo Info regarding a specific Lido deployment
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromLido(
 | 
			
		||||
        LidoInfo memory lidoInfo,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (uint256[] memory)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
 | 
			
		||||
        if (takerToken != lidoInfo.wethToken || makerToken != address(lidoInfo.stEthToken)) {
 | 
			
		||||
            // Return 0 values if not buying stETH for WETH
 | 
			
		||||
            uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
            uint256[] memory takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
            return takerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Minting stETH is always 1:1 therefore we can just return the same amounts back
 | 
			
		||||
        return makerTokenAmounts;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,132 +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 "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
 | 
			
		||||
import "@0x/contracts-zero-ex/contracts/src/vendor/ILiquidityProvider.sol";
 | 
			
		||||
import "./ApproximateBuys.sol";
 | 
			
		||||
import "./SamplerUtils.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract LiquidityProviderSampler is
 | 
			
		||||
    SamplerUtils,
 | 
			
		||||
    ApproximateBuys
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Default gas limit for liquidity provider calls.
 | 
			
		||||
    uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from an arbitrary on-chain liquidity provider.
 | 
			
		||||
    /// @param providerAddress Address of the liquidity provider.
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromLiquidityProvider(
 | 
			
		||||
        address providerAddress,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        // Initialize array of maker token amounts.
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            try
 | 
			
		||||
                ILiquidityProvider(providerAddress).getSellQuote
 | 
			
		||||
                    {gas: DEFAULT_CALL_GAS}
 | 
			
		||||
                    (
 | 
			
		||||
                        IERC20TokenV06(takerToken),
 | 
			
		||||
                        IERC20TokenV06(makerToken),
 | 
			
		||||
                        takerTokenAmounts[i]
 | 
			
		||||
                    )
 | 
			
		||||
                returns (uint256 amount)
 | 
			
		||||
            {
 | 
			
		||||
                makerTokenAmounts[i] = amount;
 | 
			
		||||
                // Break early if there are 0 amounts
 | 
			
		||||
                if (makerTokenAmounts[i] == 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from an arbitrary on-chain liquidity provider.
 | 
			
		||||
    /// @param providerAddress Address of the liquidity provider.
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromLiquidityProvider(
 | 
			
		||||
        address providerAddress,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        takerTokenAmounts = _sampleApproximateBuys(
 | 
			
		||||
            ApproximateBuyQuoteOpts({
 | 
			
		||||
                makerTokenData: abi.encode(makerToken, providerAddress),
 | 
			
		||||
                takerTokenData: abi.encode(takerToken, providerAddress),
 | 
			
		||||
                getSellQuoteCallback: _sampleSellForApproximateBuyFromLiquidityProvider
 | 
			
		||||
            }),
 | 
			
		||||
            makerTokenAmounts
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sampleSellForApproximateBuyFromLiquidityProvider(
 | 
			
		||||
        bytes memory takerTokenData,
 | 
			
		||||
        bytes memory makerTokenData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        (address takerToken, address providerAddress) =
 | 
			
		||||
            abi.decode(takerTokenData, (address, address));
 | 
			
		||||
        (address makerToken) =
 | 
			
		||||
            abi.decode(makerTokenData, (address));
 | 
			
		||||
        try
 | 
			
		||||
            this.sampleSellsFromLiquidityProvider
 | 
			
		||||
                {gas: DEFAULT_CALL_GAS}
 | 
			
		||||
                (providerAddress, takerToken, makerToken, _toSingleValueArray(sellAmount))
 | 
			
		||||
            returns (uint256[] memory amounts)
 | 
			
		||||
        {
 | 
			
		||||
            return amounts[0];
 | 
			
		||||
        } catch (bytes memory) {
 | 
			
		||||
            // Swallow failures, leaving all results as zero.
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,127 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./interfaces/IMStable.sol";
 | 
			
		||||
import "./ApproximateBuys.sol";
 | 
			
		||||
import "./SamplerUtils.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MStableSampler is
 | 
			
		||||
    SamplerUtils,
 | 
			
		||||
    ApproximateBuys
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Default gas limit for mStable calls.
 | 
			
		||||
    uint256 constant private DEFAULT_CALL_GAS = 800e3; // 800k
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from the mStable contract
 | 
			
		||||
    /// @param router Address of the mStable contract
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromMStable(
 | 
			
		||||
        address router,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        // Initialize array of maker token amounts.
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            try
 | 
			
		||||
                IMStable(router).getSwapOutput
 | 
			
		||||
                    {gas: DEFAULT_CALL_GAS}
 | 
			
		||||
                    (takerToken, makerToken, takerTokenAmounts[i])
 | 
			
		||||
                returns (uint256 amount)
 | 
			
		||||
            {
 | 
			
		||||
                makerTokenAmounts[i] = amount;
 | 
			
		||||
                // Break early if there are 0 amounts
 | 
			
		||||
                if (makerTokenAmounts[i] == 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from MStable contract
 | 
			
		||||
    /// @param router Address of the mStable contract
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromMStable(
 | 
			
		||||
        address router,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        return _sampleApproximateBuys(
 | 
			
		||||
            ApproximateBuyQuoteOpts({
 | 
			
		||||
                makerTokenData: abi.encode(makerToken, router),
 | 
			
		||||
                takerTokenData: abi.encode(takerToken, router),
 | 
			
		||||
                getSellQuoteCallback: _sampleSellForApproximateBuyFromMStable
 | 
			
		||||
            }),
 | 
			
		||||
            makerTokenAmounts
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sampleSellForApproximateBuyFromMStable(
 | 
			
		||||
        bytes memory takerTokenData,
 | 
			
		||||
        bytes memory makerTokenData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        (address takerToken, address router) =
 | 
			
		||||
            abi.decode(takerTokenData, (address, address));
 | 
			
		||||
        (address makerToken) =
 | 
			
		||||
            abi.decode(makerTokenData, (address));
 | 
			
		||||
        try
 | 
			
		||||
            this.sampleSellsFromMStable
 | 
			
		||||
                (router, takerToken, makerToken, _toSingleValueArray(sellAmount))
 | 
			
		||||
            returns (uint256[] memory amounts)
 | 
			
		||||
        {
 | 
			
		||||
            return amounts[0];
 | 
			
		||||
        } catch (bytes memory) {
 | 
			
		||||
            // Swallow failures, leaving all results as zero.
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,267 +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-utils/contracts/src/v06/LibMathV06.sol";
 | 
			
		||||
 | 
			
		||||
interface IPSM {
 | 
			
		||||
    // @dev Get the fee for selling USDC to DAI in PSM
 | 
			
		||||
    // @return tin toll in [wad]
 | 
			
		||||
    function tin() external view returns (uint256);
 | 
			
		||||
    // @dev Get the fee for selling DAI to USDC in PSM
 | 
			
		||||
    // @return tout toll out [wad]
 | 
			
		||||
    function tout() external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    // @dev Get the address of the PSM state Vat
 | 
			
		||||
    // @return address of the Vat
 | 
			
		||||
    function vat() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    // @dev Get the address of the underlying vault powering PSM
 | 
			
		||||
    // @return address of gemJoin contract
 | 
			
		||||
    function gemJoin() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    // @dev Get the address of DAI
 | 
			
		||||
    // @return address of DAI contract
 | 
			
		||||
    function dai() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    // @dev Sell USDC for DAI
 | 
			
		||||
    // @param usr The address of the account trading USDC for DAI.
 | 
			
		||||
    // @param gemAmt The amount of USDC to sell in USDC base units
 | 
			
		||||
    function sellGem(
 | 
			
		||||
        address usr,
 | 
			
		||||
        uint256 gemAmt
 | 
			
		||||
    ) external;
 | 
			
		||||
    // @dev Buy USDC for DAI
 | 
			
		||||
    // @param usr The address of the account trading DAI for USDC
 | 
			
		||||
    // @param gemAmt The amount of USDC to buy in USDC base units
 | 
			
		||||
    function buyGem(
 | 
			
		||||
        address usr,
 | 
			
		||||
        uint256 gemAmt
 | 
			
		||||
    ) external;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IVAT {
 | 
			
		||||
    // @dev Get a collateral type by identifier
 | 
			
		||||
    // @param ilkIdentifier bytes32 identifier. Example: ethers.utils.formatBytes32String("PSM-USDC-A")
 | 
			
		||||
    // @return ilk
 | 
			
		||||
    // @return ilk.Art Total Normalised Debt in wad
 | 
			
		||||
    // @return ilk.rate Accumulated Rates in ray
 | 
			
		||||
    // @return ilk.spot Price with Safety Margin in ray
 | 
			
		||||
    // @return ilk.line Debt Ceiling in rad
 | 
			
		||||
    // @return ilk.dust Urn Debt Floor in rad
 | 
			
		||||
    function ilks(
 | 
			
		||||
        bytes32 ilkIdentifier
 | 
			
		||||
    ) external view returns (
 | 
			
		||||
        uint256 Art,
 | 
			
		||||
        uint256 rate,
 | 
			
		||||
        uint256 spot,
 | 
			
		||||
        uint256 line,
 | 
			
		||||
        uint256 dust
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract MakerPSMSampler is
 | 
			
		||||
    SamplerUtils
 | 
			
		||||
{
 | 
			
		||||
    using LibSafeMathV06 for uint256;
 | 
			
		||||
 | 
			
		||||
    /// @dev Information about which PSM module to use
 | 
			
		||||
    struct MakerPsmInfo {
 | 
			
		||||
        address psmAddress;
 | 
			
		||||
        bytes32 ilkIdentifier;
 | 
			
		||||
        address gemTokenAddress;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gas limit for MakerPsm calls.
 | 
			
		||||
    uint256 constant private MAKER_PSM_CALL_GAS = 300e3; // 300k
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Maker units
 | 
			
		||||
    // wad: fixed point decimal with 18 decimals (for basic quantities, e.g. balances)
 | 
			
		||||
    uint256 constant private WAD = 10 ** 18;
 | 
			
		||||
    // ray: fixed point decimal with 27 decimals (for precise quantites, e.g. ratios)
 | 
			
		||||
    uint256 constant private RAY = 10 ** 27;
 | 
			
		||||
    // rad: fixed point decimal with 45 decimals (result of integer multiplication with a wad and a ray)
 | 
			
		||||
    uint256 constant private RAD = 10 ** 45;
 | 
			
		||||
    // See https://github.com/makerdao/dss/blob/master/DEVELOPING.m
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from Maker PSM
 | 
			
		||||
    function sampleSellsFromMakerPsm(
 | 
			
		||||
        MakerPsmInfo memory psmInfo,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        IPSM psm = IPSM(psmInfo.psmAddress);
 | 
			
		||||
        IVAT vat = IVAT(psm.vat());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        if (makerToken != psm.dai() && takerToken != psm.dai()) {
 | 
			
		||||
            return makerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            uint256 buyAmount = _samplePSMSell(psmInfo, makerToken, takerToken, takerTokenAmounts[i], psm, vat);
 | 
			
		||||
 | 
			
		||||
            if (buyAmount == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            makerTokenAmounts[i] = buyAmount;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function sampleBuysFromMakerPsm(
 | 
			
		||||
        MakerPsmInfo memory psmInfo,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        IPSM psm = IPSM(psmInfo.psmAddress);
 | 
			
		||||
        IVAT vat = IVAT(psm.vat());
 | 
			
		||||
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        if (makerToken != psm.dai() && takerToken != psm.dai()) {
 | 
			
		||||
            return takerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            uint256 sellAmount = _samplePSMBuy(psmInfo, makerToken, takerToken, makerTokenAmounts[i], psm, vat);
 | 
			
		||||
 | 
			
		||||
            if (sellAmount == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            takerTokenAmounts[i] = sellAmount;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _samplePSMSell(MakerPsmInfo memory psmInfo, address makerToken, address takerToken, uint256 takerTokenAmount, IPSM psm, IVAT vat)
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        (uint256 totalDebtInWad,,, uint256 debtCeilingInRad, uint256 debtFloorInRad) = vat.ilks(psmInfo.ilkIdentifier);
 | 
			
		||||
        uint256 gemTokenBaseUnit = uint256(1e6);
 | 
			
		||||
 | 
			
		||||
        if (takerToken == psmInfo.gemTokenAddress) {
 | 
			
		||||
            // Simulate sellGem
 | 
			
		||||
            // Selling USDC to the PSM, increasing the total debt
 | 
			
		||||
            // Convert USDC 6 decimals to 18 decimals [wad]
 | 
			
		||||
            uint256 takerTokenAmountInWad = takerTokenAmount.safeMul(1e12);
 | 
			
		||||
 | 
			
		||||
            uint256 newTotalDebtInRad = totalDebtInWad.safeAdd(takerTokenAmountInWad).safeMul(RAY);
 | 
			
		||||
 | 
			
		||||
            // PSM is too full to fit
 | 
			
		||||
            if (newTotalDebtInRad >= debtCeilingInRad) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            uint256 feeInWad = takerTokenAmountInWad.safeMul(psm.tin()).safeDiv(WAD);
 | 
			
		||||
            uint256 makerTokenAmountInWad = takerTokenAmountInWad.safeSub(feeInWad);
 | 
			
		||||
 | 
			
		||||
            return makerTokenAmountInWad;
 | 
			
		||||
        } else if (makerToken == psmInfo.gemTokenAddress) {
 | 
			
		||||
            // Simulate buyGem
 | 
			
		||||
            // Buying USDC from the PSM, decreasing the total debt
 | 
			
		||||
            // Selling DAI for USDC, already in 18 decimals [wad]
 | 
			
		||||
            uint256 takerTokenAmountInWad = takerTokenAmount;
 | 
			
		||||
            if (takerTokenAmountInWad > totalDebtInWad) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
            uint256 newTotalDebtInRad = totalDebtInWad.safeSub(takerTokenAmountInWad).safeMul(RAY);
 | 
			
		||||
 | 
			
		||||
            // PSM is empty, not enough USDC to buy from it
 | 
			
		||||
            if (newTotalDebtInRad <= debtFloorInRad) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            uint256 feeDivisorInWad = WAD.safeAdd(psm.tout()); // eg. 1.001 * 10 ** 18 with 0.1% tout;
 | 
			
		||||
            uint256 makerTokenAmountInGemTokenBaseUnits =  takerTokenAmountInWad.safeMul(gemTokenBaseUnit).safeDiv(feeDivisorInWad);
 | 
			
		||||
 | 
			
		||||
            return makerTokenAmountInGemTokenBaseUnits;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _samplePSMBuy(MakerPsmInfo memory psmInfo, address makerToken, address takerToken, uint256 makerTokenAmount, IPSM psm, IVAT vat)
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        (uint256 totalDebtInWad,,, uint256 debtCeilingInRad, uint256 debtFloorInRad) = vat.ilks(psmInfo.ilkIdentifier);
 | 
			
		||||
 | 
			
		||||
        if (takerToken == psmInfo.gemTokenAddress) {
 | 
			
		||||
            // Simulate sellGem
 | 
			
		||||
            // Selling USDC to the PSM, increasing the total debt
 | 
			
		||||
            uint256 makerTokenAmountInWad = makerTokenAmount;
 | 
			
		||||
            uint256 feeDivisorInWad = WAD.safeSub(psm.tin()); // eg. 0.999 * 10 ** 18 with 0.1% tin;
 | 
			
		||||
            uint256 takerTokenAmountInWad = makerTokenAmountInWad.safeMul(WAD).safeDiv(feeDivisorInWad);
 | 
			
		||||
            uint256 newTotalDebtInRad = totalDebtInWad.safeAdd(takerTokenAmountInWad).safeMul(RAY);
 | 
			
		||||
 | 
			
		||||
            // PSM is too full to fit
 | 
			
		||||
            if (newTotalDebtInRad >= debtCeilingInRad) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            uint256 takerTokenAmountInGemInGemBaseUnits = (takerTokenAmountInWad.safeDiv(1e12)).safeAdd(1); // Add 1 to deal with cut off decimals converting to lower decimals
 | 
			
		||||
 | 
			
		||||
            return takerTokenAmountInGemInGemBaseUnits;
 | 
			
		||||
        } else if (makerToken == psmInfo.gemTokenAddress) {
 | 
			
		||||
            // Simulate buyGem
 | 
			
		||||
            // Buying USDC from the PSM, decreasing the total debt
 | 
			
		||||
            uint256 makerTokenAmountInWad = makerTokenAmount.safeMul(1e12);
 | 
			
		||||
            uint256 feeMultiplierInWad = WAD.safeAdd(psm.tout()); // eg. 1.001 * 10 ** 18 with 0.1% tout;
 | 
			
		||||
            uint256 takerTokenAmountInWad =  makerTokenAmountInWad.safeMul(feeMultiplierInWad).safeDiv(WAD);
 | 
			
		||||
            if (takerTokenAmountInWad > totalDebtInWad) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
            uint256 newTotalDebtInRad = totalDebtInWad.safeSub(takerTokenAmountInWad).safeMul(RAY);
 | 
			
		||||
 | 
			
		||||
            // PSM is empty, not enough USDC to buy
 | 
			
		||||
            if (newTotalDebtInRad <= debtFloorInRad) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            return takerTokenAmountInWad;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,169 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./interfaces/IMooniswap.sol";
 | 
			
		||||
import "./ApproximateBuys.sol";
 | 
			
		||||
import "./SamplerUtils.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MooniswapSampler is
 | 
			
		||||
    SamplerUtils,
 | 
			
		||||
    ApproximateBuys
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Gas limit for Mooniswap calls.
 | 
			
		||||
    uint256 constant private MOONISWAP_CALL_GAS = 150e3; // 150k
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from Mooniswap.
 | 
			
		||||
    /// @param registry Address of the Mooniswap Registry.
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return pool The contract address for the pool
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromMooniswap(
 | 
			
		||||
        address registry,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (IMooniswap pool, uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            uint256 buyAmount = sampleSingleSellFromMooniswapPool(
 | 
			
		||||
                registry,
 | 
			
		||||
                takerToken,
 | 
			
		||||
                makerToken,
 | 
			
		||||
                takerTokenAmounts[i]
 | 
			
		||||
            );
 | 
			
		||||
            makerTokenAmounts[i] = buyAmount;
 | 
			
		||||
            // Break early if there are 0 amounts
 | 
			
		||||
            if (makerTokenAmounts[i] == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pool = IMooniswap(
 | 
			
		||||
            IMooniswapRegistry(registry).pools(takerToken, makerToken)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function sampleSingleSellFromMooniswapPool(
 | 
			
		||||
        address registry,
 | 
			
		||||
        address mooniswapTakerToken,
 | 
			
		||||
        address mooniswapMakerToken,
 | 
			
		||||
        uint256 takerTokenAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        // Find the pool for the pair.
 | 
			
		||||
        IMooniswap pool = IMooniswap(
 | 
			
		||||
            IMooniswapRegistry(registry).pools(mooniswapTakerToken, mooniswapMakerToken)
 | 
			
		||||
        );
 | 
			
		||||
        // If there is no pool then return early
 | 
			
		||||
        if (address(pool) == address(0)) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        uint256 poolBalance = mooniswapTakerToken == address(0)
 | 
			
		||||
            ? address(pool).balance
 | 
			
		||||
            : IERC20TokenV06(mooniswapTakerToken).balanceOf(address(pool));
 | 
			
		||||
        // If the pool balance is smaller than the sell amount
 | 
			
		||||
        // don't sample to avoid multiplication overflow in buys
 | 
			
		||||
        if (poolBalance < takerTokenAmount) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        try
 | 
			
		||||
            pool.getReturn
 | 
			
		||||
                {gas: MOONISWAP_CALL_GAS}
 | 
			
		||||
                (mooniswapTakerToken, mooniswapMakerToken, takerTokenAmount)
 | 
			
		||||
            returns (uint256 amount)
 | 
			
		||||
        {
 | 
			
		||||
            return amount;
 | 
			
		||||
        } catch (bytes memory) {
 | 
			
		||||
            // Swallow failures, leaving all results as zero.
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from Mooniswap.
 | 
			
		||||
    /// @param registry Address of the Mooniswap Registry.
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token sell amount for each sample.
 | 
			
		||||
    /// @return pool The contract address for the pool
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromMooniswap(
 | 
			
		||||
        address registry,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (IMooniswap pool, uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        takerTokenAmounts = _sampleApproximateBuys(
 | 
			
		||||
            ApproximateBuyQuoteOpts({
 | 
			
		||||
                makerTokenData: abi.encode(registry, makerToken),
 | 
			
		||||
                takerTokenData: abi.encode(registry, takerToken),
 | 
			
		||||
                getSellQuoteCallback: _sampleSellForApproximateBuyFromMooniswap
 | 
			
		||||
            }),
 | 
			
		||||
            makerTokenAmounts
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        pool = IMooniswap(
 | 
			
		||||
            IMooniswapRegistry(registry).pools(takerToken, makerToken)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sampleSellForApproximateBuyFromMooniswap(
 | 
			
		||||
        bytes memory takerTokenData,
 | 
			
		||||
        bytes memory makerTokenData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        (address registry, address mooniswapTakerToken) = abi.decode(takerTokenData, (address, address));
 | 
			
		||||
        (address _registry, address mooniswapMakerToken) = abi.decode(makerTokenData, (address, address));
 | 
			
		||||
        return sampleSingleSellFromMooniswapPool(
 | 
			
		||||
            registry,
 | 
			
		||||
            mooniswapTakerToken,
 | 
			
		||||
            mooniswapMakerToken,
 | 
			
		||||
            sellAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,82 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./interfaces/IMultiBridge.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MultiBridgeSampler {
 | 
			
		||||
 | 
			
		||||
    /// @dev Default gas limit for multibridge calls.
 | 
			
		||||
    uint256 constant private DEFAULT_CALL_GAS = 400e3; // 400k
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from MultiBridge.
 | 
			
		||||
    /// @param multibridge Address of the MultiBridge contract.
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param intermediateToken The address of the intermediate token to
 | 
			
		||||
    ///        use in an indirect route.
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromMultiBridge(
 | 
			
		||||
        address multibridge,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address intermediateToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        // Initialize array of maker token amounts.
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        // If no address provided, return all zeros.
 | 
			
		||||
        if (multibridge == address(0)) {
 | 
			
		||||
            return makerTokenAmounts;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            (bool didSucceed, bytes memory resultData) =
 | 
			
		||||
                multibridge.staticcall.gas(DEFAULT_CALL_GAS)(
 | 
			
		||||
                    abi.encodeWithSelector(
 | 
			
		||||
                        IMultiBridge(0).getSellQuote.selector,
 | 
			
		||||
                        takerToken,
 | 
			
		||||
                        intermediateToken,
 | 
			
		||||
                        makerToken,
 | 
			
		||||
                        takerTokenAmounts[i]
 | 
			
		||||
                    ));
 | 
			
		||||
            uint256 buyAmount = 0;
 | 
			
		||||
            if (didSucceed) {
 | 
			
		||||
                buyAmount = abi.decode(resultData, (uint256));
 | 
			
		||||
            }
 | 
			
		||||
            // Exit early if the amount is too high for the source to serve
 | 
			
		||||
            if (buyAmount == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            makerTokenAmounts[i] = buyAmount;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,239 +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";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IExchange {
 | 
			
		||||
 | 
			
		||||
    enum OrderStatus {
 | 
			
		||||
        INVALID,
 | 
			
		||||
        FILLABLE,
 | 
			
		||||
        FILLED,
 | 
			
		||||
        CANCELLED,
 | 
			
		||||
        EXPIRED
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev A standard OTC or OO limit order.
 | 
			
		||||
    struct LimitOrder {
 | 
			
		||||
        IERC20TokenV06 makerToken;
 | 
			
		||||
        IERC20TokenV06 takerToken;
 | 
			
		||||
        uint128 makerAmount;
 | 
			
		||||
        uint128 takerAmount;
 | 
			
		||||
        uint128 takerTokenFeeAmount;
 | 
			
		||||
        address maker;
 | 
			
		||||
        address taker;
 | 
			
		||||
        address sender;
 | 
			
		||||
        address feeRecipient;
 | 
			
		||||
        bytes32 pool;
 | 
			
		||||
        uint64 expiry;
 | 
			
		||||
        uint256 salt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev An RFQ limit order.
 | 
			
		||||
    struct RfqOrder {
 | 
			
		||||
        IERC20TokenV06 makerToken;
 | 
			
		||||
        IERC20TokenV06 takerToken;
 | 
			
		||||
        uint128 makerAmount;
 | 
			
		||||
        uint128 takerAmount;
 | 
			
		||||
        address maker;
 | 
			
		||||
        address taker;
 | 
			
		||||
        address txOrigin;
 | 
			
		||||
        bytes32 pool;
 | 
			
		||||
        uint64 expiry;
 | 
			
		||||
        uint256 salt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Info on a limit or RFQ order.
 | 
			
		||||
    struct OrderInfo {
 | 
			
		||||
        bytes32 orderHash;
 | 
			
		||||
        OrderStatus status;
 | 
			
		||||
        uint128 takerTokenFilledAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Allowed signature types.
 | 
			
		||||
    enum SignatureType {
 | 
			
		||||
        ILLEGAL,
 | 
			
		||||
        INVALID,
 | 
			
		||||
        EIP712,
 | 
			
		||||
        ETHSIGN
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Encoded EC signature.
 | 
			
		||||
    struct Signature {
 | 
			
		||||
        // How to validate the signature.
 | 
			
		||||
        SignatureType signatureType;
 | 
			
		||||
        // EC Signature data.
 | 
			
		||||
        uint8 v;
 | 
			
		||||
        // EC Signature data.
 | 
			
		||||
        bytes32 r;
 | 
			
		||||
        // EC Signature data.
 | 
			
		||||
        bytes32 s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the order info for a limit order.
 | 
			
		||||
    /// @param order The limit order.
 | 
			
		||||
    /// @return orderInfo Info about the order.
 | 
			
		||||
    function getLimitOrderInfo(LimitOrder memory order)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (OrderInfo memory orderInfo);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get order info, fillable amount, and signature validity for a limit order.
 | 
			
		||||
    ///      Fillable amount is determined using balances and allowances of the maker.
 | 
			
		||||
    /// @param order The limit order.
 | 
			
		||||
    /// @param signature The order signature.
 | 
			
		||||
    /// @return orderInfo Info about the order.
 | 
			
		||||
    /// @return actualFillableTakerTokenAmount How much of the order is fillable
 | 
			
		||||
    ///         based on maker funds, in taker tokens.
 | 
			
		||||
    /// @return isSignatureValid Whether the signature is valid.
 | 
			
		||||
    function getLimitOrderRelevantState(
 | 
			
		||||
        LimitOrder memory order,
 | 
			
		||||
        Signature calldata signature
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (
 | 
			
		||||
            OrderInfo memory orderInfo,
 | 
			
		||||
            uint128 actualFillableTakerTokenAmount,
 | 
			
		||||
            bool isSignatureValid
 | 
			
		||||
        );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract NativeOrderSampler {
 | 
			
		||||
    using LibSafeMathV06 for uint256;
 | 
			
		||||
    using LibBytesV06 for bytes;
 | 
			
		||||
 | 
			
		||||
    /// @dev Gas limit for calls to `getOrderFillableTakerAmount()`.
 | 
			
		||||
    uint256 constant internal DEFAULT_CALL_GAS = 200e3; // 200k
 | 
			
		||||
 | 
			
		||||
    /// @dev Queries the fillable taker asset amounts of native orders.
 | 
			
		||||
    ///      Effectively ignores orders that have empty signatures or
 | 
			
		||||
    ///      maker/taker asset amounts (returning 0).
 | 
			
		||||
    /// @param orders Native limit orders to query.
 | 
			
		||||
    /// @param orderSignatures Signatures for each respective order in `orders`.
 | 
			
		||||
    /// @param exchange The V4 exchange.
 | 
			
		||||
    /// @return orderFillableTakerAssetAmounts How much taker asset can be filled
 | 
			
		||||
    ///         by each order in `orders`.
 | 
			
		||||
    function getLimitOrderFillableTakerAssetAmounts(
 | 
			
		||||
        IExchange.LimitOrder[] memory orders,
 | 
			
		||||
        IExchange.Signature[] memory orderSignatures,
 | 
			
		||||
        IExchange exchange
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory orderFillableTakerAssetAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        orderFillableTakerAssetAmounts = new uint256[](orders.length);
 | 
			
		||||
        for (uint256 i = 0; i != orders.length; i++) {
 | 
			
		||||
            try
 | 
			
		||||
                this.getLimitOrderFillableTakerAmount
 | 
			
		||||
                    {gas: DEFAULT_CALL_GAS}
 | 
			
		||||
                    (
 | 
			
		||||
                       orders[i],
 | 
			
		||||
                       orderSignatures[i],
 | 
			
		||||
                       exchange
 | 
			
		||||
                    )
 | 
			
		||||
                returns (uint256 amount)
 | 
			
		||||
            {
 | 
			
		||||
                orderFillableTakerAssetAmounts[i] = amount;
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                orderFillableTakerAssetAmounts[i] = 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Queries the fillable taker asset amounts of native orders.
 | 
			
		||||
    ///      Effectively ignores orders that have empty signatures or
 | 
			
		||||
    /// @param orders Native orders to query.
 | 
			
		||||
    /// @param orderSignatures Signatures for each respective order in `orders`.
 | 
			
		||||
    /// @param exchange The V4 exchange.
 | 
			
		||||
    /// @return orderFillableMakerAssetAmounts How much maker asset can be filled
 | 
			
		||||
    ///         by each order in `orders`.
 | 
			
		||||
    function getLimitOrderFillableMakerAssetAmounts(
 | 
			
		||||
        IExchange.LimitOrder[] memory orders,
 | 
			
		||||
        IExchange.Signature[] memory orderSignatures,
 | 
			
		||||
        IExchange exchange
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory orderFillableMakerAssetAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        orderFillableMakerAssetAmounts = getLimitOrderFillableTakerAssetAmounts(
 | 
			
		||||
            orders,
 | 
			
		||||
            orderSignatures,
 | 
			
		||||
            exchange
 | 
			
		||||
        );
 | 
			
		||||
        // `orderFillableMakerAssetAmounts` now holds taker asset amounts, so
 | 
			
		||||
        // convert them to maker asset amounts.
 | 
			
		||||
        for (uint256 i = 0; i < orders.length; ++i) {
 | 
			
		||||
            if (orderFillableMakerAssetAmounts[i] != 0) {
 | 
			
		||||
                orderFillableMakerAssetAmounts[i] = LibMathV06.getPartialAmountCeil(
 | 
			
		||||
                    orderFillableMakerAssetAmounts[i],
 | 
			
		||||
                    orders[i].takerAmount,
 | 
			
		||||
                    orders[i].makerAmount
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the fillable taker amount of an order, taking into account
 | 
			
		||||
    ///      order state, maker fees, and maker balances.
 | 
			
		||||
    function getLimitOrderFillableTakerAmount(
 | 
			
		||||
        IExchange.LimitOrder memory order,
 | 
			
		||||
        IExchange.Signature memory signature,
 | 
			
		||||
        IExchange exchange
 | 
			
		||||
    )
 | 
			
		||||
        virtual
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 fillableTakerAmount)
 | 
			
		||||
    {
 | 
			
		||||
        if (signature.signatureType == IExchange.SignatureType.ILLEGAL ||
 | 
			
		||||
            signature.signatureType == IExchange.SignatureType.INVALID ||
 | 
			
		||||
            order.makerAmount == 0 ||
 | 
			
		||||
            order.takerAmount == 0)
 | 
			
		||||
        {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        (
 | 
			
		||||
            IExchange.OrderInfo memory orderInfo,
 | 
			
		||||
            uint128 remainingFillableTakerAmount,
 | 
			
		||||
            bool isSignatureValid
 | 
			
		||||
        ) = exchange.getLimitOrderRelevantState(order, signature);
 | 
			
		||||
 | 
			
		||||
        if (
 | 
			
		||||
              orderInfo.status != IExchange.OrderStatus.FILLABLE ||
 | 
			
		||||
              !isSignatureValid ||
 | 
			
		||||
              order.makerToken == IERC20TokenV06(0)
 | 
			
		||||
            ) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fillableTakerAmount = uint256(remainingFillableTakerAmount);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,58 +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 "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract SamplerUtils {
 | 
			
		||||
 | 
			
		||||
    /// @dev Overridable way to get token decimals.
 | 
			
		||||
    /// @param tokenAddress Address of the token.
 | 
			
		||||
    /// @return decimals The decimal places for the token.
 | 
			
		||||
    function _getTokenDecimals(address tokenAddress)
 | 
			
		||||
        virtual
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint8 decimals)
 | 
			
		||||
    {
 | 
			
		||||
        return LibERC20TokenV06.compatDecimals(IERC20TokenV06(tokenAddress));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _toSingleValueArray(uint256 v)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (uint256[] memory arr)
 | 
			
		||||
    {
 | 
			
		||||
        arr = new uint256[](1);
 | 
			
		||||
        arr[0] = v;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Assert that the tokens in a trade pair are valid.
 | 
			
		||||
    /// @param makerToken Address of the maker token.
 | 
			
		||||
    /// @param takerToken Address of the taker token.
 | 
			
		||||
    function _assertValidPair(address makerToken, address takerToken)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
    {
 | 
			
		||||
        require(makerToken != takerToken, "ERC20BridgeSampler/INVALID_TOKEN_PAIR");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,126 +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 "./ApproximateBuys.sol";
 | 
			
		||||
import "./interfaces/IShell.sol";
 | 
			
		||||
import "./SamplerUtils.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ShellSampler is
 | 
			
		||||
    SamplerUtils,
 | 
			
		||||
    ApproximateBuys
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    struct ShellInfo {
 | 
			
		||||
        address poolAddress;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Default gas limit for Shell calls.
 | 
			
		||||
    uint256 constant private DEFAULT_CALL_GAS = 300e3; // 300k
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from the Shell pool contract
 | 
			
		||||
    /// @param pool Address of the Shell pool contract
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromShell(
 | 
			
		||||
        address pool,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        // Initialize array of maker token amounts.
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            try
 | 
			
		||||
                IShell(pool).viewOriginSwap
 | 
			
		||||
                    {gas: DEFAULT_CALL_GAS}
 | 
			
		||||
                    (takerToken, makerToken, takerTokenAmounts[i])
 | 
			
		||||
                returns (uint256 amount)
 | 
			
		||||
            {
 | 
			
		||||
                makerTokenAmounts[i] = amount;
 | 
			
		||||
            } catch (bytes memory) {
 | 
			
		||||
                // Swallow failures, leaving all results as zero.
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from Shell pool contract
 | 
			
		||||
    /// @param pool Address of the Shell pool contract
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromShell(
 | 
			
		||||
        address pool,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        return _sampleApproximateBuys(
 | 
			
		||||
            ApproximateBuyQuoteOpts({
 | 
			
		||||
                makerTokenData: abi.encode(makerToken, pool),
 | 
			
		||||
                takerTokenData: abi.encode(takerToken, pool),
 | 
			
		||||
                getSellQuoteCallback: _sampleSellForApproximateBuyFromShell
 | 
			
		||||
            }),
 | 
			
		||||
            makerTokenAmounts
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sampleSellForApproximateBuyFromShell(
 | 
			
		||||
        bytes memory takerTokenData,
 | 
			
		||||
        bytes memory makerTokenData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        (address takerToken, address pool) = abi.decode(takerTokenData, (address, address));
 | 
			
		||||
        (address makerToken) = abi.decode(makerTokenData, (address));
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
            this.sampleSellsFromShell
 | 
			
		||||
                (pool, takerToken, makerToken, _toSingleValueArray(sellAmount))
 | 
			
		||||
            returns (uint256[] memory amounts)
 | 
			
		||||
        {
 | 
			
		||||
            return amounts[0];
 | 
			
		||||
        } catch (bytes memory) {
 | 
			
		||||
            // Swallow failures, leaving all results as zero.
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,156 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
// import "./interfaces/ISmoothy.sol";
 | 
			
		||||
import "./ApproximateBuys.sol";
 | 
			
		||||
import "./SamplerUtils.sol";
 | 
			
		||||
import "./interfaces/ISmoothy.sol";
 | 
			
		||||
 | 
			
		||||
contract SmoothySampler is
 | 
			
		||||
    SamplerUtils,
 | 
			
		||||
    ApproximateBuys
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Information for sampling from smoothy sources.
 | 
			
		||||
    struct SmoothyInfo {
 | 
			
		||||
        address poolAddress;
 | 
			
		||||
        bytes4 sellQuoteFunctionSelector;
 | 
			
		||||
        bytes4 buyQuoteFunctionSelector;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Base gas limit for Smoothy calls.
 | 
			
		||||
    uint256 constant private SMOOTHY_CALL_GAS = 600e3;
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from Smoothy.
 | 
			
		||||
    /// @param smoothyInfo Smoothy information specific to this token pair.
 | 
			
		||||
    /// @param fromTokenIdx Index of the taker token (what to sell).
 | 
			
		||||
    /// @param toTokenIdx Index of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromSmoothy(
 | 
			
		||||
        SmoothyInfo memory smoothyInfo,
 | 
			
		||||
        int128 fromTokenIdx,
 | 
			
		||||
        int128 toTokenIdx,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        // Basically a Curve fork
 | 
			
		||||
 | 
			
		||||
        // Smoothy only keep a percentage of its tokens available in reserve
 | 
			
		||||
        uint256 poolReserveMakerAmount = ISmoothy(smoothyInfo.poolAddress).getBalance(uint256(toTokenIdx)) -
 | 
			
		||||
                                         ISmoothy(smoothyInfo.poolAddress)._yBalances(uint256(toTokenIdx));
 | 
			
		||||
        (, , , uint256 decimals) = ISmoothy(smoothyInfo.poolAddress).getTokenStats(uint256(toTokenIdx));
 | 
			
		||||
        poolReserveMakerAmount = poolReserveMakerAmount/(10**(18-decimals));
 | 
			
		||||
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            (bool didSucceed, bytes memory resultData) =
 | 
			
		||||
                smoothyInfo.poolAddress.staticcall.gas(SMOOTHY_CALL_GAS)(
 | 
			
		||||
                    abi.encodeWithSelector(
 | 
			
		||||
                        smoothyInfo.sellQuoteFunctionSelector,
 | 
			
		||||
                        fromTokenIdx,
 | 
			
		||||
                        toTokenIdx,
 | 
			
		||||
                        takerTokenAmounts[i]
 | 
			
		||||
                    ));
 | 
			
		||||
            uint256 buyAmount = 0;
 | 
			
		||||
            if (didSucceed) {
 | 
			
		||||
                buyAmount = abi.decode(resultData, (uint256));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Make sure the quoted buyAmount is available in the pool reserve
 | 
			
		||||
            if (buyAmount >= poolReserveMakerAmount) {
 | 
			
		||||
                // Assign pool reserve amount for all higher samples to break early
 | 
			
		||||
                for (uint256 j = i; j < numSamples; j++) {
 | 
			
		||||
                    makerTokenAmounts[j] = poolReserveMakerAmount;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            } else {
 | 
			
		||||
                makerTokenAmounts[i] = buyAmount;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Break early if there are 0 amounts
 | 
			
		||||
            if (makerTokenAmounts[i] == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from Smoothy.
 | 
			
		||||
    /// @param smoothyInfo Smoothy information specific to this token pair.
 | 
			
		||||
    /// @param fromTokenIdx Index of the taker token (what to sell).
 | 
			
		||||
    /// @param toTokenIdx Index of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromSmoothy(
 | 
			
		||||
        SmoothyInfo memory smoothyInfo,
 | 
			
		||||
        int128 fromTokenIdx,
 | 
			
		||||
        int128 toTokenIdx,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        // Buys not supported so approximate it.
 | 
			
		||||
        return _sampleApproximateBuys(
 | 
			
		||||
            ApproximateBuyQuoteOpts({
 | 
			
		||||
                makerTokenData: abi.encode(toTokenIdx, smoothyInfo),
 | 
			
		||||
                takerTokenData: abi.encode(fromTokenIdx, smoothyInfo),
 | 
			
		||||
                getSellQuoteCallback: _sampleSellForApproximateBuyFromSmoothy
 | 
			
		||||
            }),
 | 
			
		||||
            makerTokenAmounts
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sampleSellForApproximateBuyFromSmoothy(
 | 
			
		||||
        bytes memory takerTokenData,
 | 
			
		||||
        bytes memory makerTokenData,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        (int128 takerTokenIdx, SmoothyInfo memory smoothyInfo) =
 | 
			
		||||
            abi.decode(takerTokenData, (int128, SmoothyInfo));
 | 
			
		||||
        (int128 makerTokenIdx) =
 | 
			
		||||
            abi.decode(makerTokenData, (int128));
 | 
			
		||||
        (bool success, bytes memory resultData) =
 | 
			
		||||
            address(this).staticcall(abi.encodeWithSelector(
 | 
			
		||||
                this.sampleSellsFromSmoothy.selector,
 | 
			
		||||
                smoothyInfo,
 | 
			
		||||
                takerTokenIdx,
 | 
			
		||||
                makerTokenIdx,
 | 
			
		||||
                _toSingleValueArray(sellAmount)
 | 
			
		||||
            ));
 | 
			
		||||
        if (!success) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        // solhint-disable-next-line indent
 | 
			
		||||
        return abi.decode(resultData, (uint256[]))[0];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,124 +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 "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TwoHopSampler {
 | 
			
		||||
    using LibBytesV06 for bytes;
 | 
			
		||||
 | 
			
		||||
    struct HopInfo {
 | 
			
		||||
        uint256 sourceIndex;
 | 
			
		||||
        bytes returnData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function sampleTwoHopSell(
 | 
			
		||||
        bytes[] memory firstHopCalls,
 | 
			
		||||
        bytes[] memory secondHopCalls,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (
 | 
			
		||||
            HopInfo memory firstHop,
 | 
			
		||||
            HopInfo memory secondHop,
 | 
			
		||||
            uint256 buyAmount
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        uint256 intermediateAssetAmount = 0;
 | 
			
		||||
        for (uint256 i = 0; i != firstHopCalls.length; ++i) {
 | 
			
		||||
            firstHopCalls[i].writeUint256(firstHopCalls[i].length - 32, sellAmount);
 | 
			
		||||
            (bool didSucceed, bytes memory returnData) = address(this).call(firstHopCalls[i]);
 | 
			
		||||
            if (didSucceed) {
 | 
			
		||||
                uint256 amount = returnData.readUint256(returnData.length - 32);
 | 
			
		||||
                if (amount > intermediateAssetAmount) {
 | 
			
		||||
                    intermediateAssetAmount = amount;
 | 
			
		||||
                    firstHop.sourceIndex = i;
 | 
			
		||||
                    firstHop.returnData = returnData;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (intermediateAssetAmount == 0) {
 | 
			
		||||
            return (firstHop, secondHop, buyAmount);
 | 
			
		||||
        }
 | 
			
		||||
        for (uint256 j = 0; j != secondHopCalls.length; ++j) {
 | 
			
		||||
            secondHopCalls[j].writeUint256(secondHopCalls[j].length - 32, intermediateAssetAmount);
 | 
			
		||||
            (bool didSucceed, bytes memory returnData) = address(this).call(secondHopCalls[j]);
 | 
			
		||||
            if (didSucceed) {
 | 
			
		||||
                uint256 amount = returnData.readUint256(returnData.length - 32);
 | 
			
		||||
                if (amount > buyAmount) {
 | 
			
		||||
                    buyAmount = amount;
 | 
			
		||||
                    secondHop.sourceIndex = j;
 | 
			
		||||
                    secondHop.returnData = returnData;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function sampleTwoHopBuy(
 | 
			
		||||
        bytes[] memory firstHopCalls,
 | 
			
		||||
        bytes[] memory secondHopCalls,
 | 
			
		||||
        uint256 buyAmount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (
 | 
			
		||||
            HopInfo memory firstHop,
 | 
			
		||||
            HopInfo memory secondHop,
 | 
			
		||||
            uint256 sellAmount
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        sellAmount = uint256(-1);
 | 
			
		||||
        uint256 intermediateAssetAmount = uint256(-1);
 | 
			
		||||
        for (uint256 j = 0; j != secondHopCalls.length; ++j) {
 | 
			
		||||
            secondHopCalls[j].writeUint256(secondHopCalls[j].length - 32, buyAmount);
 | 
			
		||||
            (bool didSucceed, bytes memory returnData) = address(this).call(secondHopCalls[j]);
 | 
			
		||||
            if (didSucceed) {
 | 
			
		||||
                uint256 amount = returnData.readUint256(returnData.length - 32);
 | 
			
		||||
                if (
 | 
			
		||||
                    amount > 0 &&
 | 
			
		||||
                    amount < intermediateAssetAmount
 | 
			
		||||
                ) {
 | 
			
		||||
                    intermediateAssetAmount = amount;
 | 
			
		||||
                    secondHop.sourceIndex = j;
 | 
			
		||||
                    secondHop.returnData = returnData;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (intermediateAssetAmount == uint256(-1)) {
 | 
			
		||||
            return (firstHop, secondHop, sellAmount);
 | 
			
		||||
        }
 | 
			
		||||
        for (uint256 i = 0; i != firstHopCalls.length; ++i) {
 | 
			
		||||
            firstHopCalls[i].writeUint256(firstHopCalls[i].length - 32, intermediateAssetAmount);
 | 
			
		||||
            (bool didSucceed, bytes memory returnData) = address(this).call(firstHopCalls[i]);
 | 
			
		||||
            if (didSucceed) {
 | 
			
		||||
                uint256 amount = returnData.readUint256(returnData.length - 32);
 | 
			
		||||
                if (
 | 
			
		||||
                    amount > 0 &&
 | 
			
		||||
                    amount < sellAmount
 | 
			
		||||
                ) {
 | 
			
		||||
                    sellAmount = amount;
 | 
			
		||||
                    firstHop.sourceIndex = i;
 | 
			
		||||
                    firstHop.returnData = returnData;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,214 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./interfaces/IUniswapExchangeQuotes.sol";
 | 
			
		||||
import "./SamplerUtils.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IUniswapExchangeFactory {
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the exchange for a token.
 | 
			
		||||
    /// @param tokenAddress The address of the token contract.
 | 
			
		||||
    function getExchange(address tokenAddress)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract UniswapSampler is
 | 
			
		||||
    SamplerUtils
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Gas limit for Uniswap calls.
 | 
			
		||||
    uint256 constant private UNISWAP_CALL_GAS = 150e3; // 150k
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from Uniswap.
 | 
			
		||||
    /// @param router Address of the Uniswap Router
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromUniswap(
 | 
			
		||||
        address router,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        IUniswapExchangeQuotes takerTokenExchange = takerToken == address(0) ?
 | 
			
		||||
            IUniswapExchangeQuotes(0) : _getUniswapExchange(router, takerToken);
 | 
			
		||||
        IUniswapExchangeQuotes makerTokenExchange = makerToken == address(0) ?
 | 
			
		||||
            IUniswapExchangeQuotes(0) : _getUniswapExchange(router, makerToken);
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            bool didSucceed = true;
 | 
			
		||||
            if (makerToken == address(0)) {
 | 
			
		||||
                (makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
 | 
			
		||||
                    address(takerTokenExchange),
 | 
			
		||||
                    takerTokenExchange.getTokenToEthInputPrice.selector,
 | 
			
		||||
                    takerTokenAmounts[i]
 | 
			
		||||
                );
 | 
			
		||||
            } else if (takerToken == address(0)) {
 | 
			
		||||
                (makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
 | 
			
		||||
                    address(makerTokenExchange),
 | 
			
		||||
                    makerTokenExchange.getEthToTokenInputPrice.selector,
 | 
			
		||||
                    takerTokenAmounts[i]
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                uint256 ethBought;
 | 
			
		||||
                (ethBought, didSucceed) = _callUniswapExchangePriceFunction(
 | 
			
		||||
                    address(takerTokenExchange),
 | 
			
		||||
                    takerTokenExchange.getTokenToEthInputPrice.selector,
 | 
			
		||||
                    takerTokenAmounts[i]
 | 
			
		||||
                );
 | 
			
		||||
                if (ethBought != 0) {
 | 
			
		||||
                    (makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
 | 
			
		||||
                        address(makerTokenExchange),
 | 
			
		||||
                        makerTokenExchange.getEthToTokenInputPrice.selector,
 | 
			
		||||
                        ethBought
 | 
			
		||||
                    );
 | 
			
		||||
                } else {
 | 
			
		||||
                    makerTokenAmounts[i] = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // Break early if amounts are 0
 | 
			
		||||
            if (!didSucceed || makerTokenAmounts[i] == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from Uniswap.
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param makerTokenAmounts Maker token sell amount for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromUniswap(
 | 
			
		||||
        address router,
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        _assertValidPair(makerToken, takerToken);
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
 | 
			
		||||
        IUniswapExchangeQuotes takerTokenExchange = takerToken == address(0) ?
 | 
			
		||||
            IUniswapExchangeQuotes(0) : _getUniswapExchange(router, takerToken);
 | 
			
		||||
        IUniswapExchangeQuotes makerTokenExchange = makerToken == address(0) ?
 | 
			
		||||
            IUniswapExchangeQuotes(0) : _getUniswapExchange(router, makerToken);
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            bool didSucceed = true;
 | 
			
		||||
            if (makerToken == address(0)) {
 | 
			
		||||
                (takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
 | 
			
		||||
                    address(takerTokenExchange),
 | 
			
		||||
                    takerTokenExchange.getTokenToEthOutputPrice.selector,
 | 
			
		||||
                    makerTokenAmounts[i]
 | 
			
		||||
                );
 | 
			
		||||
            } else if (takerToken == address(0)) {
 | 
			
		||||
                (takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
 | 
			
		||||
                    address(makerTokenExchange),
 | 
			
		||||
                    makerTokenExchange.getEthToTokenOutputPrice.selector,
 | 
			
		||||
                    makerTokenAmounts[i]
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                uint256 ethSold;
 | 
			
		||||
                (ethSold, didSucceed) = _callUniswapExchangePriceFunction(
 | 
			
		||||
                    address(makerTokenExchange),
 | 
			
		||||
                    makerTokenExchange.getEthToTokenOutputPrice.selector,
 | 
			
		||||
                    makerTokenAmounts[i]
 | 
			
		||||
                );
 | 
			
		||||
                if (ethSold != 0) {
 | 
			
		||||
                    (takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
 | 
			
		||||
                        address(takerTokenExchange),
 | 
			
		||||
                        takerTokenExchange.getTokenToEthOutputPrice.selector,
 | 
			
		||||
                        ethSold
 | 
			
		||||
                    );
 | 
			
		||||
                } else {
 | 
			
		||||
                    takerTokenAmounts[i] = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // Break early if amounts are 0
 | 
			
		||||
            if (!didSucceed || takerTokenAmounts[i] == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gracefully calls a Uniswap pricing function.
 | 
			
		||||
    /// @param uniswapExchangeAddress Address of an `IUniswapExchangeQuotes` exchange.
 | 
			
		||||
    /// @param functionSelector Selector of the target function.
 | 
			
		||||
    /// @param inputAmount Quantity parameter particular to the pricing function.
 | 
			
		||||
    /// @return outputAmount The returned amount from the function call. Will be
 | 
			
		||||
    ///         zero if the call fails or if `uniswapExchangeAddress` is zero.
 | 
			
		||||
    function _callUniswapExchangePriceFunction(
 | 
			
		||||
        address uniswapExchangeAddress,
 | 
			
		||||
        bytes4 functionSelector,
 | 
			
		||||
        uint256 inputAmount
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 outputAmount, bool didSucceed)
 | 
			
		||||
    {
 | 
			
		||||
        if (uniswapExchangeAddress == address(0)) {
 | 
			
		||||
            return (outputAmount, didSucceed);
 | 
			
		||||
        }
 | 
			
		||||
        bytes memory resultData;
 | 
			
		||||
        (didSucceed, resultData) =
 | 
			
		||||
            uniswapExchangeAddress.staticcall.gas(UNISWAP_CALL_GAS)(
 | 
			
		||||
                abi.encodeWithSelector(
 | 
			
		||||
                    functionSelector,
 | 
			
		||||
                    inputAmount
 | 
			
		||||
                ));
 | 
			
		||||
        if (didSucceed) {
 | 
			
		||||
            outputAmount = abi.decode(resultData, (uint256));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrive an existing Uniswap exchange contract.
 | 
			
		||||
    ///      Throws if the exchange does not exist.
 | 
			
		||||
    /// @param router Address of the Uniswap router.
 | 
			
		||||
    /// @param tokenAddress Address of the token contract.
 | 
			
		||||
    /// @return exchange `IUniswapExchangeQuotes` for the token.
 | 
			
		||||
    function _getUniswapExchange(address router, address tokenAddress)
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (IUniswapExchangeQuotes exchange)
 | 
			
		||||
    {
 | 
			
		||||
        exchange = IUniswapExchangeQuotes(
 | 
			
		||||
            address(IUniswapExchangeFactory(router)
 | 
			
		||||
            .getExchange(tokenAddress))
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,102 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./interfaces/IUniswapV2Router01.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract UniswapV2Sampler
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Gas limit for UniswapV2 calls.
 | 
			
		||||
    uint256 constant private UNISWAPV2_CALL_GAS = 150e3; // 150k
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from UniswapV2.
 | 
			
		||||
    /// @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 makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromUniswapV2(
 | 
			
		||||
        address router,
 | 
			
		||||
        address[] memory path,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory makerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 numSamples = takerTokenAmounts.length;
 | 
			
		||||
        makerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            try
 | 
			
		||||
                IUniswapV2Router01(router).getAmountsOut
 | 
			
		||||
                    {gas: UNISWAPV2_CALL_GAS}
 | 
			
		||||
                    (takerTokenAmounts[i], 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 UniswapV2.
 | 
			
		||||
    /// @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 takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromUniswapV2(
 | 
			
		||||
        address router,
 | 
			
		||||
        address[] memory path,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory takerTokenAmounts)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 numSamples = makerTokenAmounts.length;
 | 
			
		||||
        takerTokenAmounts = new uint256[](numSamples);
 | 
			
		||||
        for (uint256 i = 0; i < numSamples; i++) {
 | 
			
		||||
            try
 | 
			
		||||
                IUniswapV2Router01(router).getAmountsIn
 | 
			
		||||
                    {gas: UNISWAPV2_CALL_GAS}
 | 
			
		||||
                    (makerTokenAmounts[i], 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;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,313 +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/IERC20TokenV06.sol";
 | 
			
		||||
 | 
			
		||||
interface IUniswapV3Quoter {
 | 
			
		||||
    function factory()
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (IUniswapV3Factory factory);
 | 
			
		||||
    function quoteExactInput(bytes memory path, uint256 amountIn)
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 amountOut);
 | 
			
		||||
    function quoteExactOutput(bytes memory path, uint256 amountOut)
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 amountIn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IUniswapV3Factory {
 | 
			
		||||
    function getPool(IERC20TokenV06 a, IERC20TokenV06 b, uint24 fee)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (IUniswapV3Pool pool);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IUniswapV3Pool {
 | 
			
		||||
    function token0() external view returns (IERC20TokenV06);
 | 
			
		||||
    function token1() external view returns (IERC20TokenV06);
 | 
			
		||||
    function fee() external view returns (uint24);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract UniswapV3Sampler
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Gas limit for UniswapV3 calls. This is 100% a guess.
 | 
			
		||||
    uint256 constant private QUOTE_GAS = 300e3;
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample sell quotes from UniswapV3.
 | 
			
		||||
    /// @param quoter UniswapV3 Quoter contract.
 | 
			
		||||
    /// @param path Token route. Should be takerToken -> makerToken
 | 
			
		||||
    /// @param takerTokenAmounts Taker token sell amount for each sample.
 | 
			
		||||
    /// @return uniswapPaths The encoded uniswap path for each sample.
 | 
			
		||||
    /// @return makerTokenAmounts Maker amounts bought at each taker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleSellsFromUniswapV3(
 | 
			
		||||
        IUniswapV3Quoter quoter,
 | 
			
		||||
        IERC20TokenV06[] memory path,
 | 
			
		||||
        uint256[] memory takerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (
 | 
			
		||||
            bytes[] memory uniswapPaths,
 | 
			
		||||
            uint256[] memory makerTokenAmounts
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        IUniswapV3Pool[][] memory poolPaths =
 | 
			
		||||
            _getValidPoolPaths(quoter.factory(), path, 0);
 | 
			
		||||
 | 
			
		||||
        makerTokenAmounts = new uint256[](takerTokenAmounts.length);
 | 
			
		||||
        uniswapPaths = new bytes[](takerTokenAmounts.length);
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < takerTokenAmounts.length; ++i) {
 | 
			
		||||
            // Pick the best result from all the paths.
 | 
			
		||||
            bytes memory topUniswapPath;
 | 
			
		||||
            uint256 topBuyAmount = 0;
 | 
			
		||||
            for (uint256 j = 0; j < poolPaths.length; ++j) {
 | 
			
		||||
                bytes memory uniswapPath = _toUniswapPath(path, poolPaths[j]);
 | 
			
		||||
                try
 | 
			
		||||
                    quoter.quoteExactInput
 | 
			
		||||
                        { gas: QUOTE_GAS }
 | 
			
		||||
                        (uniswapPath, takerTokenAmounts[i])
 | 
			
		||||
                        returns (uint256 buyAmount)
 | 
			
		||||
                {
 | 
			
		||||
                    if (topBuyAmount <= buyAmount) {
 | 
			
		||||
                        topBuyAmount = buyAmount;
 | 
			
		||||
                        topUniswapPath = uniswapPath;
 | 
			
		||||
                    }
 | 
			
		||||
                } catch { }
 | 
			
		||||
            }
 | 
			
		||||
            // Break early if we can't complete the buys.
 | 
			
		||||
            if (topBuyAmount == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            makerTokenAmounts[i] = topBuyAmount;
 | 
			
		||||
            uniswapPaths[i] = topUniswapPath;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sample buy quotes from UniswapV3.
 | 
			
		||||
    /// @param quoter UniswapV3 Quoter contract.
 | 
			
		||||
    /// @param path Token route. Should be takerToken -> makerToken.
 | 
			
		||||
    /// @param makerTokenAmounts Maker token buy amount for each sample.
 | 
			
		||||
    /// @return uniswapPaths The encoded uniswap path for each sample.
 | 
			
		||||
    /// @return takerTokenAmounts Taker amounts sold at each maker token
 | 
			
		||||
    ///         amount.
 | 
			
		||||
    function sampleBuysFromUniswapV3(
 | 
			
		||||
        IUniswapV3Quoter quoter,
 | 
			
		||||
        IERC20TokenV06[] memory path,
 | 
			
		||||
        uint256[] memory makerTokenAmounts
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (
 | 
			
		||||
            bytes[] memory uniswapPaths,
 | 
			
		||||
            uint256[] memory takerTokenAmounts
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        IUniswapV3Pool[][] memory poolPaths =
 | 
			
		||||
            _getValidPoolPaths(quoter.factory(), path, 0);
 | 
			
		||||
        IERC20TokenV06[] memory reversedPath = _reverseTokenPath(path);
 | 
			
		||||
 | 
			
		||||
        takerTokenAmounts = new uint256[](makerTokenAmounts.length);
 | 
			
		||||
        uniswapPaths = new bytes[](makerTokenAmounts.length);
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < makerTokenAmounts.length; ++i) {
 | 
			
		||||
            // Pick the best result from all the paths.
 | 
			
		||||
            bytes memory topUniswapPath;
 | 
			
		||||
            uint256 topSellAmount = 0;
 | 
			
		||||
            for (uint256 j = 0; j < poolPaths.length; ++j) {
 | 
			
		||||
                // quoter requires path to be reversed for buys.
 | 
			
		||||
                bytes memory uniswapPath = _toUniswapPath(
 | 
			
		||||
                    reversedPath,
 | 
			
		||||
                    _reversePoolPath(poolPaths[j])
 | 
			
		||||
                );
 | 
			
		||||
                try
 | 
			
		||||
                    quoter.quoteExactOutput
 | 
			
		||||
                        { gas: QUOTE_GAS }
 | 
			
		||||
                        (uniswapPath, makerTokenAmounts[i])
 | 
			
		||||
                        returns (uint256 sellAmount)
 | 
			
		||||
                {
 | 
			
		||||
                    if (topSellAmount == 0 || topSellAmount >= sellAmount) {
 | 
			
		||||
                        topSellAmount = sellAmount;
 | 
			
		||||
                        // But the output path should still be encoded for sells.
 | 
			
		||||
                        topUniswapPath = _toUniswapPath(path, poolPaths[j]);
 | 
			
		||||
                    }
 | 
			
		||||
                } catch {}
 | 
			
		||||
            }
 | 
			
		||||
            // Break early if we can't complete the buys.
 | 
			
		||||
            if (topSellAmount == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            takerTokenAmounts[i] = topSellAmount;
 | 
			
		||||
            uniswapPaths[i] = topUniswapPath;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _getValidPoolPaths(
 | 
			
		||||
        IUniswapV3Factory factory,
 | 
			
		||||
        IERC20TokenV06[] memory tokenPath,
 | 
			
		||||
        uint256 startIndex
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (IUniswapV3Pool[][] memory poolPaths)
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            tokenPath.length - startIndex >= 2,
 | 
			
		||||
            "UniswapV3Sampler/tokenPath too short"
 | 
			
		||||
        );
 | 
			
		||||
        uint24[3] memory validPoolFees = [
 | 
			
		||||
            // The launch pool fees. Could get hairier if they add more.
 | 
			
		||||
            uint24(0.0005e6),
 | 
			
		||||
            uint24(0.003e6),
 | 
			
		||||
            uint24(0.01e6)
 | 
			
		||||
        ];
 | 
			
		||||
        IUniswapV3Pool[] memory validPools =
 | 
			
		||||
            new IUniswapV3Pool[](validPoolFees.length);
 | 
			
		||||
        uint256 numValidPools = 0;
 | 
			
		||||
        {
 | 
			
		||||
            IERC20TokenV06 inputToken = tokenPath[startIndex];
 | 
			
		||||
            IERC20TokenV06 outputToken = tokenPath[startIndex + 1];
 | 
			
		||||
            for (uint256 i = 0; i < validPoolFees.length; ++i) {
 | 
			
		||||
                IUniswapV3Pool pool =
 | 
			
		||||
                factory.getPool(inputToken, outputToken, validPoolFees[i]);
 | 
			
		||||
                if (_isValidPool(pool)) {
 | 
			
		||||
                    validPools[numValidPools++] = pool;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (numValidPools == 0) {
 | 
			
		||||
            // No valid pools for this hop.
 | 
			
		||||
            return poolPaths;
 | 
			
		||||
        }
 | 
			
		||||
        if (startIndex + 2 == tokenPath.length) {
 | 
			
		||||
            // End of path.
 | 
			
		||||
            poolPaths = new IUniswapV3Pool[][](numValidPools);
 | 
			
		||||
            for (uint256 i = 0; i < numValidPools; ++i) {
 | 
			
		||||
                poolPaths[i] = new IUniswapV3Pool[](1);
 | 
			
		||||
                poolPaths[i][0] = validPools[i];
 | 
			
		||||
            }
 | 
			
		||||
            return poolPaths;
 | 
			
		||||
        }
 | 
			
		||||
        // Get paths for subsequent hops.
 | 
			
		||||
        IUniswapV3Pool[][] memory subsequentPoolPaths =
 | 
			
		||||
            _getValidPoolPaths(factory, tokenPath, startIndex + 1);
 | 
			
		||||
        if (subsequentPoolPaths.length == 0) {
 | 
			
		||||
            // Could not complete the path.
 | 
			
		||||
            return poolPaths;
 | 
			
		||||
        }
 | 
			
		||||
        // Combine our pools with the next hop paths.
 | 
			
		||||
        poolPaths = new IUniswapV3Pool[][](
 | 
			
		||||
            numValidPools * subsequentPoolPaths.length
 | 
			
		||||
        );
 | 
			
		||||
        for (uint256 i = 0; i < numValidPools; ++i) {
 | 
			
		||||
            for (uint256 j = 0; j < subsequentPoolPaths.length; ++j) {
 | 
			
		||||
                uint256 o = i * subsequentPoolPaths.length + j;
 | 
			
		||||
                // Prepend pool to the subsequent path.
 | 
			
		||||
                poolPaths[o] =
 | 
			
		||||
                    new IUniswapV3Pool[](1 + subsequentPoolPaths[j].length);
 | 
			
		||||
                poolPaths[o][0] = validPools[i];
 | 
			
		||||
                for (uint256 k = 0; k < subsequentPoolPaths[j].length; ++k) {
 | 
			
		||||
                    poolPaths[o][1 + k] = subsequentPoolPaths[j][k];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return poolPaths;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _reverseTokenPath(IERC20TokenV06[] memory tokenPath)
 | 
			
		||||
        private
 | 
			
		||||
        returns (IERC20TokenV06[] memory reversed)
 | 
			
		||||
    {
 | 
			
		||||
        reversed = new IERC20TokenV06[](tokenPath.length);
 | 
			
		||||
        for (uint256 i = 0; i < tokenPath.length; ++i) {
 | 
			
		||||
            reversed[i] = tokenPath[tokenPath.length - i - 1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _reversePoolPath(IUniswapV3Pool[] memory poolPath)
 | 
			
		||||
        private
 | 
			
		||||
        returns (IUniswapV3Pool[] memory reversed)
 | 
			
		||||
    {
 | 
			
		||||
        reversed = new IUniswapV3Pool[](poolPath.length);
 | 
			
		||||
        for (uint256 i = 0; i < poolPath.length; ++i) {
 | 
			
		||||
            reversed[i] = poolPath[poolPath.length - i - 1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _isValidPool(IUniswapV3Pool pool)
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (bool isValid)
 | 
			
		||||
    {
 | 
			
		||||
        // Check if it has been deployed.
 | 
			
		||||
        {
 | 
			
		||||
            uint256 codeSize;
 | 
			
		||||
            assembly {
 | 
			
		||||
                codeSize := extcodesize(pool)
 | 
			
		||||
            }
 | 
			
		||||
            if (codeSize == 0) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // Must have a balance of both tokens.
 | 
			
		||||
        if (pool.token0().balanceOf(address(pool)) == 0) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (pool.token1().balanceOf(address(pool)) == 0) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _toUniswapPath(
 | 
			
		||||
        IERC20TokenV06[] memory tokenPath,
 | 
			
		||||
        IUniswapV3Pool[] memory poolPath
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes memory uniswapPath)
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            tokenPath.length >= 2 && tokenPath.length == poolPath.length + 1,
 | 
			
		||||
            "UniswapV3Sampler/invalid path lengths"
 | 
			
		||||
        );
 | 
			
		||||
        // Uniswap paths are tightly packed as:
 | 
			
		||||
        // [token0, token0token1PairFee, token1, token1Token2PairFee, token2, ...]
 | 
			
		||||
        uniswapPath = new bytes(tokenPath.length * 20 + poolPath.length * 3);
 | 
			
		||||
        uint256 o;
 | 
			
		||||
        assembly { o := add(uniswapPath, 32) }
 | 
			
		||||
        for (uint256 i = 0; i < tokenPath.length; ++i) {
 | 
			
		||||
            if (i > 0) {
 | 
			
		||||
                uint24 poolFee = poolPath[i - 1].fee();
 | 
			
		||||
                assembly {
 | 
			
		||||
                    mstore(o, shl(232, poolFee))
 | 
			
		||||
                    o := add(o, 3)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            IERC20TokenV06 token = tokenPath[i];
 | 
			
		||||
            assembly {
 | 
			
		||||
                mstore(o, shl(96, token))
 | 
			
		||||
                o := add(o, 20)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,80 +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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,44 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IBalancer {
 | 
			
		||||
    function isBound(address t) external view returns (bool);
 | 
			
		||||
    function getDenormalizedWeight(address token) external view returns (uint256);
 | 
			
		||||
    function getBalance(address token) external view returns (uint256);
 | 
			
		||||
    function getSwapFee() external view returns (uint256);
 | 
			
		||||
    function calcOutGivenIn(
 | 
			
		||||
        uint256 tokenBalanceIn,
 | 
			
		||||
        uint256 tokenWeightIn,
 | 
			
		||||
        uint256 tokenBalanceOut,
 | 
			
		||||
        uint256 tokenWeightOut,
 | 
			
		||||
        uint256 tokenAmountIn,
 | 
			
		||||
        uint256 swapFee
 | 
			
		||||
    ) external pure returns (uint256 tokenAmountOut);
 | 
			
		||||
    function calcInGivenOut(
 | 
			
		||||
        uint256 tokenBalanceIn,
 | 
			
		||||
        uint256 tokenWeightIn,
 | 
			
		||||
        uint256 tokenBalanceOut,
 | 
			
		||||
        uint256 tokenWeightOut,
 | 
			
		||||
        uint256 tokenAmountOut,
 | 
			
		||||
        uint256 swapFee
 | 
			
		||||
    ) external pure returns (uint256 tokenAmountIn);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IBancor {}
 | 
			
		||||
 | 
			
		||||
interface IBancorNetwork {
 | 
			
		||||
  function conversionPath(address _sourceToken, address _targetToken) external view returns (address[] memory);
 | 
			
		||||
  function rateByPath(address[] memory _path, uint256 _amount) external view returns (uint256);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IBancorRegistry {
 | 
			
		||||
    function getAddress(bytes32 _contractName) external view returns (address);
 | 
			
		||||
    function BANCOR_NETWORK() external view returns (bytes32);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,72 +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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable func-name-mixedcase
 | 
			
		||||
interface ICurve {
 | 
			
		||||
 | 
			
		||||
    /// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
 | 
			
		||||
    ///      This function exists on later versions of Curve (USDC/DAI/USDT)
 | 
			
		||||
    /// @param i The token index being sold.
 | 
			
		||||
    /// @param j The token index being bought.
 | 
			
		||||
    /// @param sellAmount The amount of token being bought.
 | 
			
		||||
    /// @param minBuyAmount The minimum buy amount of the token being bought.
 | 
			
		||||
    function exchange_underlying(
 | 
			
		||||
        int128 i,
 | 
			
		||||
        int128 j,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the amount of `toToken` by selling `sellAmount` of `fromToken`
 | 
			
		||||
    /// @param i The token index being sold.
 | 
			
		||||
    /// @param j The token index being bought.
 | 
			
		||||
    /// @param sellAmount The amount of token being bought.
 | 
			
		||||
    function get_dy_underlying(
 | 
			
		||||
        int128 i,
 | 
			
		||||
        int128 j,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 dy);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken`
 | 
			
		||||
    ///      This function exists on later versions of Curve (USDC/DAI/USDT)
 | 
			
		||||
    /// @param i The token index being sold.
 | 
			
		||||
    /// @param j The token index being bought.
 | 
			
		||||
    /// @param buyAmount The amount of token being bought.
 | 
			
		||||
    function get_dx_underlying(
 | 
			
		||||
        int128 i,
 | 
			
		||||
        int128 j,
 | 
			
		||||
        uint256 buyAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 dx);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the underlying token address from the token index
 | 
			
		||||
    /// @param i The token index.
 | 
			
		||||
    function underlying_coins(
 | 
			
		||||
        int128 i
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (address tokenAddress);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,96 +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;
 | 
			
		||||
 | 
			
		||||
// Keepin everything together
 | 
			
		||||
interface IKyberNetwork {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IKyberNetworkProxy {
 | 
			
		||||
 | 
			
		||||
    function getExpectedRateAfterFee(
 | 
			
		||||
        address src,
 | 
			
		||||
        address dest,
 | 
			
		||||
        uint256 srcQty,
 | 
			
		||||
        uint256 platformFeeBps,
 | 
			
		||||
        bytes calldata hint
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 expectedRate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IKyberHintHandler {
 | 
			
		||||
 | 
			
		||||
    enum TradeType {BestOfAll, MaskIn, MaskOut, Split}
 | 
			
		||||
 | 
			
		||||
    enum ProcessWithRate {NotRequired, Required}
 | 
			
		||||
 | 
			
		||||
    function getTradingReserves(
 | 
			
		||||
        address tokenSrc,
 | 
			
		||||
        address tokenDest,
 | 
			
		||||
        bool isTokenToToken,
 | 
			
		||||
        bytes calldata hint
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (
 | 
			
		||||
            bytes32[] memory reserveIds,
 | 
			
		||||
            uint256[] memory splitValuesBps,
 | 
			
		||||
            ProcessWithRate processWithRate
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    function buildTokenToEthHint(
 | 
			
		||||
        address tokenSrc,
 | 
			
		||||
        TradeType tokenToEthType,
 | 
			
		||||
        bytes32[] calldata tokenToEthReserveIds,
 | 
			
		||||
        uint256[] calldata tokenToEthSplits
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes memory hint);
 | 
			
		||||
 | 
			
		||||
    function buildEthToTokenHint(
 | 
			
		||||
        address tokenDest,
 | 
			
		||||
        TradeType ethToTokenType,
 | 
			
		||||
        bytes32[] calldata ethToTokenReserveIds,
 | 
			
		||||
        uint256[] calldata ethToTokenSplits
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes memory hint);
 | 
			
		||||
 | 
			
		||||
    function buildTokenToTokenHint(
 | 
			
		||||
        address tokenSrc,
 | 
			
		||||
        TradeType tokenToEthType,
 | 
			
		||||
        bytes32[] calldata tokenToEthReserveIds,
 | 
			
		||||
        uint256[] calldata tokenToEthSplits,
 | 
			
		||||
        address tokenDest,
 | 
			
		||||
        TradeType ethToTokenType,
 | 
			
		||||
        bytes32[] calldata ethToTokenReserveIds,
 | 
			
		||||
        uint256[] calldata ethToTokenSplits
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes memory hint);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IMStable {
 | 
			
		||||
 | 
			
		||||
    function getSwapOutput(
 | 
			
		||||
        address _input,
 | 
			
		||||
        address _output,
 | 
			
		||||
        uint256 _quantity
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 swapOutput);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,38 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IMooniswapRegistry {
 | 
			
		||||
 | 
			
		||||
    function pools(address token1, address token2) external view returns(address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IMooniswap {
 | 
			
		||||
 | 
			
		||||
    function getReturn(
 | 
			
		||||
        address fromToken,
 | 
			
		||||
        address destToken,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns(uint256 returnAmount);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,59 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IMultiBridge {
 | 
			
		||||
 | 
			
		||||
    /// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
 | 
			
		||||
    /// @param tokenAddress The address of the ERC20 token to transfer.
 | 
			
		||||
    /// @param from Address to transfer asset from.
 | 
			
		||||
    /// @param to Address to transfer asset to.
 | 
			
		||||
    /// @param amount Amount of asset to transfer.
 | 
			
		||||
    /// @param bridgeData Arbitrary asset data needed by the bridge contract.
 | 
			
		||||
    /// @return success The magic bytes `0xdc1600f3` if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success);
 | 
			
		||||
 | 
			
		||||
    /// @dev Quotes the amount of `makerToken` that would be obtained by
 | 
			
		||||
    ///      selling `sellAmount` of `takerToken`.
 | 
			
		||||
    /// @param takerToken Address of the taker token (what to sell).
 | 
			
		||||
    /// @param intermediateToken The address of the intermediate token to
 | 
			
		||||
    ///        use in an indirect route.
 | 
			
		||||
    /// @param makerToken Address of the maker token (what to buy).
 | 
			
		||||
    /// @param sellAmount Amount of `takerToken` to sell.
 | 
			
		||||
    /// @return makerTokenAmount Amount of `makerToken` that would be obtained.
 | 
			
		||||
    function getSellQuote(
 | 
			
		||||
        address takerToken,
 | 
			
		||||
        address intermediateToken,
 | 
			
		||||
        address makerToken,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 makerTokenAmount);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,43 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IShell {
 | 
			
		||||
 | 
			
		||||
    function viewOriginSwap (
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 fromAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 toAmount);
 | 
			
		||||
 | 
			
		||||
    function viewTargetSwap (
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 toAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 fromAmount);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1,45 +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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface ISmoothy {
 | 
			
		||||
 | 
			
		||||
    function getBalance (
 | 
			
		||||
        uint256 tid
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 balance);
 | 
			
		||||
 | 
			
		||||
    function _yBalances (
 | 
			
		||||
        uint256 tid
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 balance);
 | 
			
		||||
 | 
			
		||||
    function getTokenStats (
 | 
			
		||||
        uint256 tid
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 softWeight, uint256 hardWeight, uint256 balance, uint256 decimals);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,52 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IUniswapExchangeQuotes {
 | 
			
		||||
 | 
			
		||||
    function getEthToTokenInputPrice(
 | 
			
		||||
        uint256 ethSold
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 tokensBought);
 | 
			
		||||
 | 
			
		||||
    function getEthToTokenOutputPrice(
 | 
			
		||||
        uint256 tokensBought
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 ethSold);
 | 
			
		||||
 | 
			
		||||
    function getTokenToEthInputPrice(
 | 
			
		||||
        uint256 tokensSold
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 ethBought);
 | 
			
		||||
 | 
			
		||||
    function getTokenToEthOutputPrice(
 | 
			
		||||
        uint256 ethBought
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 tokensSold);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,34 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IUniswapV2Router01 {
 | 
			
		||||
 | 
			
		||||
    function getAmountsOut(uint256 amountIn, address[] calldata path)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory amounts);
 | 
			
		||||
 | 
			
		||||
    function getAmountsIn(uint256 amountOut, address[] calldata path)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory amounts);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract DummyLiquidityProvider
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Quotes the amount of `makerToken` that would be obtained by
 | 
			
		||||
    ///      selling `sellAmount` of `takerToken`.
 | 
			
		||||
    /// @param sellAmount Amount of `takerToken` to sell.
 | 
			
		||||
    /// @return makerTokenAmount Amount of `makerToken` that would be obtained.
 | 
			
		||||
    function getSellQuote(
 | 
			
		||||
        address, /* takerToken */
 | 
			
		||||
        address, /* makerToken */
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 makerTokenAmount)
 | 
			
		||||
    {
 | 
			
		||||
        makerTokenAmount = sellAmount - 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Quotes the amount of `takerToken` that would need to be sold in
 | 
			
		||||
    ///      order to obtain `buyAmount` of `makerToken`.
 | 
			
		||||
    /// @param buyAmount Amount of `makerToken` to buy.
 | 
			
		||||
    /// @return takerTokenAmount Amount of `takerToken` that would need to be sold.
 | 
			
		||||
    function getBuyQuote(
 | 
			
		||||
        address, /* takerToken */
 | 
			
		||||
        address, /* makerToken */
 | 
			
		||||
        uint256 buyAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 takerTokenAmount)
 | 
			
		||||
    {
 | 
			
		||||
        takerTokenAmount = buyAmount + 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,455 +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 "../src/ERC20BridgeSampler.sol";
 | 
			
		||||
import "../src/interfaces/IKyberNetwork.sol";
 | 
			
		||||
import "../src/interfaces/IUniswapV2Router01.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
library LibDeterministicQuotes {
 | 
			
		||||
 | 
			
		||||
    address private constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
 | 
			
		||||
    uint256 private constant RATE_DENOMINATOR = 1 ether;
 | 
			
		||||
    uint256 private constant MIN_RATE = RATE_DENOMINATOR / 100;
 | 
			
		||||
    uint256 private constant MAX_RATE = 100 * RATE_DENOMINATOR;
 | 
			
		||||
    uint8 private constant MIN_DECIMALS = 4;
 | 
			
		||||
    uint8 private constant MAX_DECIMALS = 20;
 | 
			
		||||
 | 
			
		||||
    function getDeterministicSellQuote(
 | 
			
		||||
        bytes32 salt,
 | 
			
		||||
        address sellToken,
 | 
			
		||||
        address buyToken,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (uint256 buyAmount)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 sellBase = uint256(10) ** getDeterministicTokenDecimals(sellToken);
 | 
			
		||||
        uint256 buyBase = uint256(10) ** getDeterministicTokenDecimals(buyToken);
 | 
			
		||||
        uint256 rate = getDeterministicRate(salt, sellToken, buyToken);
 | 
			
		||||
        return sellAmount * rate * buyBase / sellBase / RATE_DENOMINATOR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getDeterministicBuyQuote(
 | 
			
		||||
        bytes32 salt,
 | 
			
		||||
        address sellToken,
 | 
			
		||||
        address buyToken,
 | 
			
		||||
        uint256 buyAmount
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (uint256 sellAmount)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 sellBase = uint256(10) ** getDeterministicTokenDecimals(sellToken);
 | 
			
		||||
        uint256 buyBase = uint256(10) ** getDeterministicTokenDecimals(buyToken);
 | 
			
		||||
        uint256 rate = getDeterministicRate(salt, sellToken, buyToken);
 | 
			
		||||
        return buyAmount * RATE_DENOMINATOR * sellBase / rate / buyBase;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getDeterministicTokenDecimals(address token)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (uint8 decimals)
 | 
			
		||||
    {
 | 
			
		||||
        if (token == WETH_ADDRESS) {
 | 
			
		||||
            return 18;
 | 
			
		||||
        }
 | 
			
		||||
        bytes32 seed = keccak256(abi.encodePacked(token));
 | 
			
		||||
        return uint8(uint256(seed) % (MAX_DECIMALS - MIN_DECIMALS)) + MIN_DECIMALS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getDeterministicRate(bytes32 salt, address sellToken, address buyToken)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (uint256 rate)
 | 
			
		||||
    {
 | 
			
		||||
        bytes32 seed = keccak256(abi.encodePacked(salt, sellToken, buyToken));
 | 
			
		||||
        return uint256(seed) % (MAX_RATE - MIN_RATE) + MIN_RATE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract TestDeploymentConstants {
 | 
			
		||||
 | 
			
		||||
    // solhint-disable separate-by-one-line-in-contract
 | 
			
		||||
 | 
			
		||||
    // Mainnet addresses ///////////////////////////////////////////////////////
 | 
			
		||||
    /// @dev Mainnet address of the WETH contract.
 | 
			
		||||
    address constant private WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
 | 
			
		||||
 | 
			
		||||
    /// @dev Overridable way to get the WETH address.
 | 
			
		||||
    /// @return wethAddress The WETH address.
 | 
			
		||||
    function _getWethAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address wethAddress)
 | 
			
		||||
    {
 | 
			
		||||
        return WETH_ADDRESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract FailTrigger {
 | 
			
		||||
 | 
			
		||||
    // Give this address a balance to force operations to fail.
 | 
			
		||||
    address payable constant public FAILURE_ADDRESS = 0xe9dB8717BC5DFB20aaf538b4a5a02B7791FF430C;
 | 
			
		||||
 | 
			
		||||
    // Funds `FAILURE_ADDRESS`.
 | 
			
		||||
    function enableFailTrigger() external payable {
 | 
			
		||||
        FAILURE_ADDRESS.transfer(msg.value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _revertIfShouldFail() internal view {
 | 
			
		||||
        if (FAILURE_ADDRESS.balance != 0) {
 | 
			
		||||
            revert("FAIL_TRIGGERED");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestERC20BridgeSamplerUniswapExchange is
 | 
			
		||||
    IUniswapExchangeQuotes,
 | 
			
		||||
    TestDeploymentConstants,
 | 
			
		||||
    FailTrigger
 | 
			
		||||
{
 | 
			
		||||
    bytes32 constant private BASE_SALT = 0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab;
 | 
			
		||||
 | 
			
		||||
    address public tokenAddress;
 | 
			
		||||
    bytes32 public salt;
 | 
			
		||||
 | 
			
		||||
    constructor(address _tokenAddress) public {
 | 
			
		||||
        tokenAddress = _tokenAddress;
 | 
			
		||||
        salt = keccak256(abi.encodePacked(BASE_SALT, _tokenAddress));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Deterministic `IUniswapExchangeQuotes.getEthToTokenInputPrice()`.
 | 
			
		||||
    function getEthToTokenInputPrice(
 | 
			
		||||
        uint256 ethSold
 | 
			
		||||
    )
 | 
			
		||||
        override
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 tokensBought)
 | 
			
		||||
    {
 | 
			
		||||
        _revertIfShouldFail();
 | 
			
		||||
        return LibDeterministicQuotes.getDeterministicSellQuote(
 | 
			
		||||
            salt,
 | 
			
		||||
            tokenAddress,
 | 
			
		||||
            _getWethAddress(),
 | 
			
		||||
            ethSold
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Deterministic `IUniswapExchangeQuotes.getEthToTokenOutputPrice()`.
 | 
			
		||||
    function getEthToTokenOutputPrice(
 | 
			
		||||
        uint256 tokensBought
 | 
			
		||||
    )
 | 
			
		||||
        override
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 ethSold)
 | 
			
		||||
    {
 | 
			
		||||
        _revertIfShouldFail();
 | 
			
		||||
        return LibDeterministicQuotes.getDeterministicBuyQuote(
 | 
			
		||||
            salt,
 | 
			
		||||
            _getWethAddress(),
 | 
			
		||||
            tokenAddress,
 | 
			
		||||
            tokensBought
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Deterministic `IUniswapExchangeQuotes.getTokenToEthInputPrice()`.
 | 
			
		||||
    function getTokenToEthInputPrice(
 | 
			
		||||
        uint256 tokensSold
 | 
			
		||||
    )
 | 
			
		||||
        override
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 ethBought)
 | 
			
		||||
    {
 | 
			
		||||
        _revertIfShouldFail();
 | 
			
		||||
        return LibDeterministicQuotes.getDeterministicSellQuote(
 | 
			
		||||
            salt,
 | 
			
		||||
            tokenAddress,
 | 
			
		||||
            _getWethAddress(),
 | 
			
		||||
            tokensSold
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Deterministic `IUniswapExchangeQuotes.getTokenToEthOutputPrice()`.
 | 
			
		||||
    function getTokenToEthOutputPrice(
 | 
			
		||||
        uint256 ethBought
 | 
			
		||||
    )
 | 
			
		||||
        override
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 tokensSold)
 | 
			
		||||
    {
 | 
			
		||||
        _revertIfShouldFail();
 | 
			
		||||
        return LibDeterministicQuotes.getDeterministicBuyQuote(
 | 
			
		||||
            salt,
 | 
			
		||||
            _getWethAddress(),
 | 
			
		||||
            tokenAddress,
 | 
			
		||||
            ethBought
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestERC20BridgeSamplerUniswapV2Router01 is
 | 
			
		||||
    IUniswapV2Router01,
 | 
			
		||||
    TestDeploymentConstants,
 | 
			
		||||
    FailTrigger
 | 
			
		||||
{
 | 
			
		||||
    bytes32 constant private SALT = 0xadc7fcb33c735913b8635927e66896b356a53a912ab2ceff929e60a04b53b3c1;
 | 
			
		||||
 | 
			
		||||
    // Deterministic `IUniswapV2Router01.getAmountsOut()`.
 | 
			
		||||
    function getAmountsOut(uint256 amountIn, address[] calldata path)
 | 
			
		||||
        override
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory amounts)
 | 
			
		||||
    {
 | 
			
		||||
        require(path.length >= 2, "PATH_TOO_SHORT");
 | 
			
		||||
        _revertIfShouldFail();
 | 
			
		||||
        amounts = new uint256[](path.length);
 | 
			
		||||
        amounts[0] = amountIn;
 | 
			
		||||
        for (uint256 i = 0; i < path.length - 1; ++i) {
 | 
			
		||||
            amounts[i + 1] = LibDeterministicQuotes.getDeterministicSellQuote(
 | 
			
		||||
                SALT,
 | 
			
		||||
                path[i],
 | 
			
		||||
                path[i + 1],
 | 
			
		||||
                amounts[i]
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Deterministic `IUniswapV2Router01.getAmountsInt()`.
 | 
			
		||||
    function getAmountsIn(uint256 amountOut, address[] calldata path)
 | 
			
		||||
        override
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory amounts)
 | 
			
		||||
    {
 | 
			
		||||
        require(path.length >= 2, "PATH_TOO_SHORT");
 | 
			
		||||
        _revertIfShouldFail();
 | 
			
		||||
        amounts = new uint256[](path.length);
 | 
			
		||||
        amounts[path.length - 1] = amountOut;
 | 
			
		||||
        for (uint256 i = path.length - 1; i > 0; --i) {
 | 
			
		||||
            amounts[i - 1] = LibDeterministicQuotes.getDeterministicBuyQuote(
 | 
			
		||||
                SALT,
 | 
			
		||||
                path[i - 1],
 | 
			
		||||
                path[i],
 | 
			
		||||
                amounts[i]
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
contract TestERC20BridgeSamplerKyberNetwork is
 | 
			
		||||
    TestDeploymentConstants,
 | 
			
		||||
    FailTrigger
 | 
			
		||||
{
 | 
			
		||||
    bytes32 constant private SALT = 0x0ff3ca9d46195c39f9a12afb74207b4970349fb3cfb1e459bbf170298d326bc7;
 | 
			
		||||
    address constant public ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
 | 
			
		||||
 | 
			
		||||
    enum TradeType {BestOfAll, MaskIn, MaskOut, Split}
 | 
			
		||||
    enum ProcessWithRate {NotRequired, Required}
 | 
			
		||||
 | 
			
		||||
    // IKyberHintHandler
 | 
			
		||||
    function buildTokenToEthHint(
 | 
			
		||||
        address tokenSrc,
 | 
			
		||||
        TradeType /* tokenToEthType */,
 | 
			
		||||
        bytes32[] calldata /* tokenToEthReserveIds */,
 | 
			
		||||
        uint256[] calldata /* tokenToEthSplits */
 | 
			
		||||
    ) external view returns (bytes memory hint)
 | 
			
		||||
    {
 | 
			
		||||
        return abi.encode(tokenSrc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function buildEthToTokenHint(
 | 
			
		||||
        address tokenDest,
 | 
			
		||||
        TradeType /* ethToTokenType */,
 | 
			
		||||
        bytes32[] calldata /* ethToTokenReserveIds */,
 | 
			
		||||
        uint256[] calldata /* ethToTokenSplits */
 | 
			
		||||
    ) external view returns (bytes memory hint)
 | 
			
		||||
    {
 | 
			
		||||
        return abi.encode(tokenDest);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // IKyberHintHandler
 | 
			
		||||
    function buildTokenToTokenHint(
 | 
			
		||||
        address tokenSrc,
 | 
			
		||||
        TradeType /* tokenToEthType */,
 | 
			
		||||
        bytes32[] calldata /* tokenToEthReserveIds */,
 | 
			
		||||
        uint256[] calldata /* tokenToEthSplits */,
 | 
			
		||||
        address /* tokenDest  */,
 | 
			
		||||
        TradeType /* EthToTokenType */,
 | 
			
		||||
        bytes32[] calldata /* EthToTokenReserveIds */,
 | 
			
		||||
        uint256[] calldata /* EthToTokenSplits */
 | 
			
		||||
    ) external view returns (bytes memory hint)
 | 
			
		||||
    {
 | 
			
		||||
        return abi.encode(tokenSrc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // IKyberHintHandler
 | 
			
		||||
    function getTradingReserves(
 | 
			
		||||
        address tokenSrc,
 | 
			
		||||
        address tokenDest,
 | 
			
		||||
        bool isTokenToToken,
 | 
			
		||||
        bytes calldata hint
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (
 | 
			
		||||
            bytes32[] memory reserveIds,
 | 
			
		||||
            uint256[] memory splitValuesBps,
 | 
			
		||||
            ProcessWithRate processWithRate
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        reserveIds = new bytes32[](1);
 | 
			
		||||
        reserveIds[0] = bytes32(uint256(1));
 | 
			
		||||
        splitValuesBps = new uint256[](0);
 | 
			
		||||
        processWithRate = ProcessWithRate.NotRequired;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Deterministic `IKyberNetworkProxy.getExpectedRateAfterFee()`.
 | 
			
		||||
    function getExpectedRateAfterFee(
 | 
			
		||||
        address fromToken,
 | 
			
		||||
        address toToken,
 | 
			
		||||
        uint256 /* srcQty */,
 | 
			
		||||
        uint256 /* fee */,
 | 
			
		||||
        bytes calldata /* hint */
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns
 | 
			
		||||
        (uint256 expectedRate)
 | 
			
		||||
    {
 | 
			
		||||
        _revertIfShouldFail();
 | 
			
		||||
        fromToken = fromToken == ETH_ADDRESS ? _getWethAddress() : fromToken;
 | 
			
		||||
        toToken = toToken == ETH_ADDRESS ? _getWethAddress() : toToken;
 | 
			
		||||
        expectedRate = LibDeterministicQuotes.getDeterministicRate(
 | 
			
		||||
            SALT,
 | 
			
		||||
            fromToken,
 | 
			
		||||
            toToken
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Deterministic `IKyberNetworkProxy.getExpectedRate()`.
 | 
			
		||||
    function getExpectedRate(
 | 
			
		||||
        address fromToken,
 | 
			
		||||
        address toToken,
 | 
			
		||||
        uint256
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 expectedRate, uint256)
 | 
			
		||||
    {
 | 
			
		||||
        _revertIfShouldFail();
 | 
			
		||||
        fromToken = fromToken == ETH_ADDRESS ? _getWethAddress() : fromToken;
 | 
			
		||||
        toToken = toToken == ETH_ADDRESS ? _getWethAddress() : toToken;
 | 
			
		||||
        expectedRate = LibDeterministicQuotes.getDeterministicRate(
 | 
			
		||||
            SALT,
 | 
			
		||||
            fromToken,
 | 
			
		||||
            toToken
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestERC20BridgeSamplerUniswapExchangeFactory is
 | 
			
		||||
    IUniswapExchangeFactory
 | 
			
		||||
{
 | 
			
		||||
    mapping (address => IUniswapExchangeQuotes) private _exchangesByToken;
 | 
			
		||||
 | 
			
		||||
    // Creates Uniswap exchange contracts for tokens.
 | 
			
		||||
    function createTokenExchanges(address[] calldata tokenAddresses)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        for (uint256 i = 0; i < tokenAddresses.length; i++) {
 | 
			
		||||
            address tokenAddress = tokenAddresses[i];
 | 
			
		||||
            _exchangesByToken[tokenAddress] =
 | 
			
		||||
                new TestERC20BridgeSamplerUniswapExchange(tokenAddress);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // `IUniswapExchangeFactory.getExchange()`.
 | 
			
		||||
    function getExchange(address tokenAddress)
 | 
			
		||||
        override
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return address(_exchangesByToken[tokenAddress]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestERC20BridgeSampler is
 | 
			
		||||
    ERC20BridgeSampler,
 | 
			
		||||
    FailTrigger
 | 
			
		||||
{
 | 
			
		||||
    TestERC20BridgeSamplerUniswapExchangeFactory public uniswap;
 | 
			
		||||
    TestERC20BridgeSamplerUniswapV2Router01 public uniswapV2Router;
 | 
			
		||||
    TestERC20BridgeSamplerKyberNetwork public kyber;
 | 
			
		||||
 | 
			
		||||
    uint8 private constant MAX_ORDER_STATUS = uint8(IExchange.OrderStatus.CANCELLED) + 1;
 | 
			
		||||
 | 
			
		||||
    constructor() public ERC20BridgeSampler() {
 | 
			
		||||
        uniswap = new TestERC20BridgeSamplerUniswapExchangeFactory();
 | 
			
		||||
        uniswapV2Router = new TestERC20BridgeSamplerUniswapV2Router01();
 | 
			
		||||
        kyber = new TestERC20BridgeSamplerKyberNetwork();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Creates Uniswap exchange contracts for tokens.
 | 
			
		||||
    function createTokenExchanges(address[] calldata tokenAddresses)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        uniswap.createTokenExchanges(tokenAddresses);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Overridden to return deterministic states.
 | 
			
		||||
    function getLimitOrderFillableTakerAmount(
 | 
			
		||||
        IExchange.LimitOrder memory order,
 | 
			
		||||
        IExchange.Signature memory,
 | 
			
		||||
        IExchange
 | 
			
		||||
    )
 | 
			
		||||
        override
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 fillableTakerAmount)
 | 
			
		||||
    {
 | 
			
		||||
        return uint256(keccak256(abi.encode(order.salt))) % order.takerAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Overriden to return deterministic decimals.
 | 
			
		||||
    function _getTokenDecimals(address tokenAddress)
 | 
			
		||||
        override
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint8 decimals)
 | 
			
		||||
    {
 | 
			
		||||
        return LibDeterministicQuotes.getDeterministicTokenDecimals(tokenAddress);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,135 +0,0 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2019 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
pragma solidity ^0.6;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "../src/NativeOrderSampler.sol";
 | 
			
		||||
import "../src/UtilitySampler.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestNativeOrderSamplerToken {
 | 
			
		||||
    mapping (address => uint256) public balanceOf;
 | 
			
		||||
    mapping (address => mapping(address => uint256)) public allowance;
 | 
			
		||||
 | 
			
		||||
    function setBalanceAndAllowance(
 | 
			
		||||
        address owner,
 | 
			
		||||
        address spender,
 | 
			
		||||
        uint256 balance,
 | 
			
		||||
        uint256 allowance_
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        balanceOf[owner] = balance;
 | 
			
		||||
        allowance[owner][spender] = allowance_;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract TestNativeOrderSampler is
 | 
			
		||||
    NativeOrderSampler,
 | 
			
		||||
    UtilitySampler
 | 
			
		||||
{
 | 
			
		||||
    uint8 private constant MAX_ORDER_STATUS = uint8(IExchange.OrderStatus.CANCELLED) + 1;
 | 
			
		||||
    bytes32 private constant VALID_SIGNATURE_HASH = bytes32(hex"01");
 | 
			
		||||
 | 
			
		||||
    function createTokens(uint256 count)
 | 
			
		||||
        external
 | 
			
		||||
        returns (TestNativeOrderSamplerToken[] memory tokens)
 | 
			
		||||
    {
 | 
			
		||||
        tokens = new TestNativeOrderSamplerToken[](count);
 | 
			
		||||
        for (uint256 i = 0; i < count; ++i) {
 | 
			
		||||
            tokens[i] = new TestNativeOrderSamplerToken();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setTokenBalanceAndAllowance(
 | 
			
		||||
        TestNativeOrderSamplerToken token,
 | 
			
		||||
        address owner,
 | 
			
		||||
        address spender,
 | 
			
		||||
        uint256 balance,
 | 
			
		||||
        uint256 allowance
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        token.setBalanceAndAllowance(owner, spender, balance, allowance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // IExchange.getLimitOrderRelevantState()
 | 
			
		||||
    function getLimitOrderRelevantState(
 | 
			
		||||
        IExchange.LimitOrder memory order,
 | 
			
		||||
        IExchange.Signature calldata signature
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (
 | 
			
		||||
            IExchange.OrderInfo memory orderInfo,
 | 
			
		||||
            uint128 actualFillableTakerTokenAmount,
 | 
			
		||||
            bool isSignatureValid
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        // The order salt determines everything.
 | 
			
		||||
        orderInfo.orderHash = keccak256(abi.encode(order.salt));
 | 
			
		||||
        if (uint8(order.salt) == 0xFF) {
 | 
			
		||||
            orderInfo.status = IExchange.OrderStatus.FILLED;
 | 
			
		||||
        } else {
 | 
			
		||||
            orderInfo.status = IExchange.OrderStatus.FILLABLE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        isSignatureValid = signature.r == VALID_SIGNATURE_HASH;
 | 
			
		||||
 | 
			
		||||
        // The expiration time is the filled taker asset amount.
 | 
			
		||||
        orderInfo.takerTokenFilledAmount = uint128(order.expiry);
 | 
			
		||||
 | 
			
		||||
        // Calculate how much is fillable in maker terms given the filled taker amount
 | 
			
		||||
        uint256 fillableMakerTokenAmount = LibMathV06.getPartialAmountFloor(
 | 
			
		||||
            uint256(
 | 
			
		||||
                order.takerAmount
 | 
			
		||||
                - orderInfo.takerTokenFilledAmount
 | 
			
		||||
            ),
 | 
			
		||||
            uint256(order.takerAmount),
 | 
			
		||||
            uint256(order.makerAmount)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Take the min of the balance/allowance and the fillable maker amount
 | 
			
		||||
        fillableMakerTokenAmount = LibSafeMathV06.min256(
 | 
			
		||||
            fillableMakerTokenAmount,
 | 
			
		||||
            _getSpendableERC20BalanceOf(order.makerToken, order.maker)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Convert to taker terms
 | 
			
		||||
        actualFillableTakerTokenAmount = LibMathV06.getPartialAmountCeil(
 | 
			
		||||
            fillableMakerTokenAmount,
 | 
			
		||||
            uint256(order.makerAmount),
 | 
			
		||||
            uint256(order.takerAmount)
 | 
			
		||||
        ).safeDowncastToUint128();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _getSpendableERC20BalanceOf(
 | 
			
		||||
        IERC20TokenV06 token,
 | 
			
		||||
        address owner
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        return LibSafeMathV06.min256(
 | 
			
		||||
            token.allowance(owner, address(this)),
 | 
			
		||||
            token.balanceOf(owner)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -39,7 +39,7 @@
 | 
			
		||||
    "config": {
 | 
			
		||||
        "publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker",
 | 
			
		||||
        "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
 | 
			
		||||
        "abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2Sampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|FakeTaker|IBalancer|IBancor|ICurve|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberDmmSampler|KyberSampler|LidoSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SmoothySampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler).json",
 | 
			
		||||
        "abis": "./test/generated-artifacts/@(BalanceChecker|FakeTaker).json",
 | 
			
		||||
        "postpublish": {
 | 
			
		||||
            "assets": []
 | 
			
		||||
        }
 | 
			
		||||
@@ -80,8 +80,9 @@
 | 
			
		||||
        "@ethersproject/contracts": "^5.0.1",
 | 
			
		||||
        "@ethersproject/providers": "^5.0.4",
 | 
			
		||||
        "@ethersproject/strings": "^5.0.10",
 | 
			
		||||
        "axios": "^0.21.1",
 | 
			
		||||
        "axios-mock-adapter": "^1.19.0",
 | 
			
		||||
        "@open-rpc/client-js": "^1.7.1",
 | 
			
		||||
        "axios": "^0.24.0",
 | 
			
		||||
        "axios-mock-adapter": "^1.20.0",
 | 
			
		||||
        "cream-sor": "^0.3.3",
 | 
			
		||||
        "decimal.js": "^10.2.0",
 | 
			
		||||
        "ethereum-types": "^3.6.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
import { ChainId } from '@0x/contract-addresses';
 | 
			
		||||
import { SignatureType } from '@0x/protocol-utils';
 | 
			
		||||
import { BigNumber, logUtils } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
@@ -11,12 +10,9 @@ import {
 | 
			
		||||
    RfqRequestOpts,
 | 
			
		||||
    SwapQuoteGetOutputOpts,
 | 
			
		||||
    SwapQuoteRequestOpts,
 | 
			
		||||
    SwapQuoterOpts,
 | 
			
		||||
} from './types';
 | 
			
		||||
import {
 | 
			
		||||
    DEFAULT_GET_MARKET_ORDERS_OPTS,
 | 
			
		||||
    DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID,
 | 
			
		||||
    DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID,
 | 
			
		||||
} from './utils/market_operation_utils/constants';
 | 
			
		||||
 | 
			
		||||
const ETH_GAS_STATION_API_URL = 'https://ethgasstation.info/api/ethgasAPI.json';
 | 
			
		||||
@@ -43,20 +39,6 @@ const PROTOCOL_FEE_MULTIPLIER = new BigNumber(0);
 | 
			
		||||
// default 50% buffer for selecting native orders to be aggregated with other sources
 | 
			
		||||
const MARKET_UTILS_AMOUNT_BUFFER_PERCENTAGE = 0.5;
 | 
			
		||||
 | 
			
		||||
const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = {
 | 
			
		||||
    chainId: ChainId.Mainnet,
 | 
			
		||||
    orderRefreshIntervalMs: 10000, // 10 seconds
 | 
			
		||||
    ...DEFAULT_ORDER_PRUNER_OPTS,
 | 
			
		||||
    samplerGasLimit: 500e6,
 | 
			
		||||
    ethGasStationUrl: ETH_GAS_STATION_API_URL,
 | 
			
		||||
    rfqt: {
 | 
			
		||||
        integratorsWhitelist: [],
 | 
			
		||||
        makerAssetOfferings: {},
 | 
			
		||||
        txOriginBlacklist: new Set(),
 | 
			
		||||
    },
 | 
			
		||||
    tokenAdjacencyGraph: DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID[ChainId.Mainnet],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const DEFAULT_EXCHANGE_PROXY_EXTENSION_CONTRACT_OPTS: ExchangeProxyContractOpts = {
 | 
			
		||||
    isFromETH: false,
 | 
			
		||||
    isToETH: false,
 | 
			
		||||
@@ -91,8 +73,6 @@ export const DEFAULT_WARNING_LOGGER: LogFunction = (obj, msg) =>
 | 
			
		||||
const EMPTY_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000';
 | 
			
		||||
export const INVALID_SIGNATURE = { signatureType: SignatureType.Invalid, v: 1, r: EMPTY_BYTES32, s: EMPTY_BYTES32 };
 | 
			
		||||
 | 
			
		||||
export { DEFAULT_FEE_SCHEDULE, DEFAULT_GAS_SCHEDULE } from './utils/market_operation_utils/constants';
 | 
			
		||||
 | 
			
		||||
export const POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS = new BigNumber(30000);
 | 
			
		||||
 | 
			
		||||
// tslint:disable-next-line: custom-no-magic-numbers
 | 
			
		||||
@@ -111,8 +91,6 @@ export const constants = {
 | 
			
		||||
    ONE_AMOUNT: new BigNumber(1),
 | 
			
		||||
    ONE_SECOND_MS,
 | 
			
		||||
    ONE_MINUTE_MS,
 | 
			
		||||
    DEFAULT_SWAP_QUOTER_OPTS,
 | 
			
		||||
    DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID,
 | 
			
		||||
    DEFAULT_SWAP_QUOTE_REQUEST_OPTS,
 | 
			
		||||
    DEFAULT_EXCHANGE_PROXY_SWAP_QUOTE_GET_OPTS,
 | 
			
		||||
    DEFAULT_EXCHANGE_PROXY_EXTENSION_CONTRACT_OPTS,
 | 
			
		||||
 
 | 
			
		||||
@@ -109,6 +109,7 @@ export {
 | 
			
		||||
    SwapQuoteGetOutputOpts,
 | 
			
		||||
    SwapQuoteInfo,
 | 
			
		||||
    SwapQuoteOrdersBreakdown,
 | 
			
		||||
    SwapQuoteMultiHopBreakdown,
 | 
			
		||||
    SwapQuoteRequestOpts,
 | 
			
		||||
    SwapQuoterError,
 | 
			
		||||
    SwapQuoterOpts,
 | 
			
		||||
@@ -116,48 +117,24 @@ export {
 | 
			
		||||
} from './types';
 | 
			
		||||
export { affiliateFeeUtils } from './utils/affiliate_fee_utils';
 | 
			
		||||
export {
 | 
			
		||||
    DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID,
 | 
			
		||||
    DEFAULT_GAS_SCHEDULE,
 | 
			
		||||
    SOURCE_FLAGS,
 | 
			
		||||
    BUY_SOURCE_FILTER_BY_CHAIN_ID,
 | 
			
		||||
    SELL_SOURCE_FILTER_BY_CHAIN_ID,
 | 
			
		||||
    NATIVE_FEE_TOKEN_BY_CHAIN_ID,
 | 
			
		||||
} from './utils/market_operation_utils/constants';
 | 
			
		||||
export {
 | 
			
		||||
    Parameters,
 | 
			
		||||
    SamplerContractCall,
 | 
			
		||||
    SamplerContractOperation,
 | 
			
		||||
} from './utils/market_operation_utils/sampler_contract_operation';
 | 
			
		||||
export {
 | 
			
		||||
    BalancerFillData,
 | 
			
		||||
    BancorFillData,
 | 
			
		||||
    CollapsedFill,
 | 
			
		||||
    CurveFillData,
 | 
			
		||||
    CurveFunctionSelectors,
 | 
			
		||||
    CurveInfo,
 | 
			
		||||
    DexSample,
 | 
			
		||||
    DODOFillData,
 | 
			
		||||
    ERC20BridgeSource,
 | 
			
		||||
    ExchangeProxyOverhead,
 | 
			
		||||
    FeeSchedule,
 | 
			
		||||
    Fill,
 | 
			
		||||
    FillData,
 | 
			
		||||
    GetMarketOrdersRfqOpts,
 | 
			
		||||
    KyberFillData,
 | 
			
		||||
    LiquidityProviderFillData,
 | 
			
		||||
    LiquidityProviderRegistry,
 | 
			
		||||
    MarketDepth,
 | 
			
		||||
    MarketDepthSide,
 | 
			
		||||
    MooniswapFillData,
 | 
			
		||||
    MultiHopFillData,
 | 
			
		||||
    NativeCollapsedFill,
 | 
			
		||||
    NativeRfqOrderFillData,
 | 
			
		||||
    NativeLimitOrderFillData,
 | 
			
		||||
    NativeFillData,
 | 
			
		||||
    OptimizedMarketOrder,
 | 
			
		||||
    SourceQuoteOperation,
 | 
			
		||||
    TokenAdjacencyGraph,
 | 
			
		||||
    UniswapV2FillData,
 | 
			
		||||
} from './utils/market_operation_utils/types';
 | 
			
		||||
export { ProtocolFeeUtils } from './utils/protocol_fee_utils';
 | 
			
		||||
export {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,12 +12,14 @@ import {
 | 
			
		||||
    FillQuoteTransformerSide,
 | 
			
		||||
    findTransformerNonce,
 | 
			
		||||
} from '@0x/protocol-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { BigNumber, hexUtils } from '@0x/utils';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { constants, POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS } from '../constants';
 | 
			
		||||
import {
 | 
			
		||||
    Address,
 | 
			
		||||
    AffiliateFeeType,
 | 
			
		||||
    Bytes,
 | 
			
		||||
    CalldataInfo,
 | 
			
		||||
    ExchangeProxyContractOpts,
 | 
			
		||||
    MarketBuySwapQuote,
 | 
			
		||||
@@ -28,23 +30,22 @@ import {
 | 
			
		||||
    SwapQuoteConsumerOpts,
 | 
			
		||||
    SwapQuoteExecutionOpts,
 | 
			
		||||
    SwapQuoteGetOutputOpts,
 | 
			
		||||
    SwapQuoteLiquidityProviderBridgeOrder,
 | 
			
		||||
    SwapQuoteUniswapV2BridgeOrder,
 | 
			
		||||
    SwapQuoteUniswapV3BridgeOrder,
 | 
			
		||||
    SwapQuoteCurveBridgeOrder,
 | 
			
		||||
    SwapQuoteMooniswapBridgeOrder,
 | 
			
		||||
    SwapQuoteHop,
 | 
			
		||||
    SwapQuoteGenericBridgeOrder,
 | 
			
		||||
    SwapQuoteOrder,
 | 
			
		||||
} from '../types';
 | 
			
		||||
import { assert } from '../utils/assert';
 | 
			
		||||
import { valueByChainId } from '../utils/utils';
 | 
			
		||||
import {
 | 
			
		||||
    CURVE_LIQUIDITY_PROVIDER_BY_CHAIN_ID,
 | 
			
		||||
    MOONISWAP_LIQUIDITY_PROVIDER_BY_CHAIN_ID,
 | 
			
		||||
    NATIVE_FEE_TOKEN_BY_CHAIN_ID,
 | 
			
		||||
} from '../utils/market_operation_utils/constants';
 | 
			
		||||
import { poolEncoder } from '../utils/market_operation_utils/orders';
 | 
			
		||||
import {
 | 
			
		||||
    CurveFillData,
 | 
			
		||||
    ERC20BridgeSource,
 | 
			
		||||
    FinalUniswapV3FillData,
 | 
			
		||||
    LiquidityProviderFillData,
 | 
			
		||||
    MooniswapFillData,
 | 
			
		||||
    OptimizedMarketBridgeOrder,
 | 
			
		||||
    OptimizedMarketOrder,
 | 
			
		||||
    UniswapV2FillData,
 | 
			
		||||
} from '../utils/market_operation_utils/types';
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
@@ -53,6 +54,7 @@ import {
 | 
			
		||||
    MultiplexSubcall,
 | 
			
		||||
    multiplexTransformERC20Encoder,
 | 
			
		||||
    multiplexUniswapEncoder,
 | 
			
		||||
    multiplexBatchSellEncoder,
 | 
			
		||||
} from './multiplex_encoders';
 | 
			
		||||
import {
 | 
			
		||||
    getFQTTransformerDataFromOptimizedOrders,
 | 
			
		||||
@@ -77,12 +79,30 @@ const PANCAKE_SWAP_FORKS = [
 | 
			
		||||
    ERC20BridgeSource.CheeseSwap,
 | 
			
		||||
    ERC20BridgeSource.JulSwap,
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const FAKE_PROVIDER: any = {
 | 
			
		||||
    sendAsync(): void {
 | 
			
		||||
        return;
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const CURVE_LIQUIDITY_PROVIDER_BY_CHAIN_ID = valueByChainId<string>(
 | 
			
		||||
    {
 | 
			
		||||
        [ChainId.Mainnet]: '0x561b94454b65614ae3db0897b74303f4acf7cc75',
 | 
			
		||||
        [ChainId.Ropsten]: '0xae241c6fc7f28f6dc0cb58b4112ba7f63fcaf5e2',
 | 
			
		||||
    },
 | 
			
		||||
    NULL_ADDRESS,
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const MOONISWAP_LIQUIDITY_PROVIDER_BY_CHAIN_ID = valueByChainId<string>(
 | 
			
		||||
    {
 | 
			
		||||
        [ChainId.Mainnet]: '0xa2033d6ba88756ce6a87584d69dc87bda9a4f889',
 | 
			
		||||
        [ChainId.Ropsten]: '0x87e0393aee0fb8c10b8653c6507c182264fe5a34',
 | 
			
		||||
    },
 | 
			
		||||
    NULL_ADDRESS,
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
    public readonly chainId: ChainId;
 | 
			
		||||
    public readonly transformerNonces: {
 | 
			
		||||
@@ -95,9 +115,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
 | 
			
		||||
    private readonly _exchangeProxy: IZeroExContract;
 | 
			
		||||
 | 
			
		||||
    constructor(public readonly contractAddresses: ContractAddresses, options: Partial<SwapQuoteConsumerOpts> = {}) {
 | 
			
		||||
        const { chainId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
 | 
			
		||||
        assert.isNumber('chainId', chainId);
 | 
			
		||||
    constructor(public readonly contractAddresses: ContractAddresses, options: SwapQuoteConsumerOpts) {
 | 
			
		||||
        const { chainId } = options;
 | 
			
		||||
        this.chainId = chainId;
 | 
			
		||||
        this.contractAddresses = contractAddresses;
 | 
			
		||||
        this._exchangeProxy = new IZeroExContract(contractAddresses.exchangeProxy, FAKE_PROVIDER);
 | 
			
		||||
@@ -151,15 +170,14 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
            ethAmount = ethAmount.plus(sellAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const slippedOrders = slipNonNativeOrders(quote);
 | 
			
		||||
 | 
			
		||||
        // VIP routes.
 | 
			
		||||
        if (
 | 
			
		||||
            this.chainId === ChainId.Mainnet &&
 | 
			
		||||
            isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap])
 | 
			
		||||
        ) {
 | 
			
		||||
            const source = slippedOrders[0].source;
 | 
			
		||||
            const fillData = (slippedOrders[0] as OptimizedMarketBridgeOrder<UniswapV2FillData>).fillData;
 | 
			
		||||
            const order = quote.hops[0].orders[0] as SwapQuoteUniswapV2BridgeOrder;
 | 
			
		||||
            const { source } = order;
 | 
			
		||||
            const { fillData } = order;
 | 
			
		||||
            return {
 | 
			
		||||
                calldataHexString: this._exchangeProxy
 | 
			
		||||
                    .sellToUniswap(
 | 
			
		||||
@@ -188,19 +206,20 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
            this.chainId === ChainId.Mainnet &&
 | 
			
		||||
            isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.UniswapV3])
 | 
			
		||||
        ) {
 | 
			
		||||
            const fillData = (slippedOrders[0] as OptimizedMarketBridgeOrder<FinalUniswapV3FillData>).fillData;
 | 
			
		||||
            const order = quote.hops[0].orders[0] as SwapQuoteUniswapV3BridgeOrder;
 | 
			
		||||
            const { fillData } = order;
 | 
			
		||||
            let _calldataHexString;
 | 
			
		||||
            if (isFromETH) {
 | 
			
		||||
                _calldataHexString = this._exchangeProxy
 | 
			
		||||
                    .sellEthForTokenToUniswapV3(fillData.uniswapPath, minBuyAmount, NULL_ADDRESS)
 | 
			
		||||
                    .sellEthForTokenToUniswapV3(fillData.encodedPath, minBuyAmount, NULL_ADDRESS)
 | 
			
		||||
                    .getABIEncodedTransactionData();
 | 
			
		||||
            } else if (isToETH) {
 | 
			
		||||
                _calldataHexString = this._exchangeProxy
 | 
			
		||||
                    .sellTokenForEthToUniswapV3(fillData.uniswapPath, sellAmount, minBuyAmount, NULL_ADDRESS)
 | 
			
		||||
                    .sellTokenForEthToUniswapV3(fillData.encodedPath, sellAmount, minBuyAmount, NULL_ADDRESS)
 | 
			
		||||
                    .getABIEncodedTransactionData();
 | 
			
		||||
            } else {
 | 
			
		||||
                _calldataHexString = this._exchangeProxy
 | 
			
		||||
                    .sellTokenForTokenToUniswapV3(fillData.uniswapPath, sellAmount, minBuyAmount, NULL_ADDRESS)
 | 
			
		||||
                    .sellTokenForTokenToUniswapV3(fillData.encodedPath, sellAmount, minBuyAmount, NULL_ADDRESS)
 | 
			
		||||
                    .getABIEncodedTransactionData();
 | 
			
		||||
            }
 | 
			
		||||
            return {
 | 
			
		||||
@@ -225,8 +244,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
                ERC20BridgeSource.JulSwap,
 | 
			
		||||
            ])
 | 
			
		||||
        ) {
 | 
			
		||||
            const source = slippedOrders[0].source;
 | 
			
		||||
            const fillData = (slippedOrders[0] as OptimizedMarketBridgeOrder<UniswapV2FillData>).fillData;
 | 
			
		||||
            const order = quote.hops[0].orders[0] as SwapQuoteUniswapV2BridgeOrder;
 | 
			
		||||
            const { source, fillData } = order;
 | 
			
		||||
            return {
 | 
			
		||||
                calldataHexString: this._exchangeProxy
 | 
			
		||||
                    .sellToPancakeSwap(
 | 
			
		||||
@@ -255,14 +274,13 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
            [ChainId.Mainnet, ChainId.BSC].includes(this.chainId) &&
 | 
			
		||||
            isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.LiquidityProvider])
 | 
			
		||||
        ) {
 | 
			
		||||
            const fillData = (slippedOrders[0] as OptimizedMarketBridgeOrder<LiquidityProviderFillData>).fillData;
 | 
			
		||||
            const target = fillData.poolAddress;
 | 
			
		||||
            const { fillData } = quote.hops[0].orders[0] as SwapQuoteLiquidityProviderBridgeOrder;
 | 
			
		||||
            return {
 | 
			
		||||
                calldataHexString: this._exchangeProxy
 | 
			
		||||
                    .sellToLiquidityProvider(
 | 
			
		||||
                        isFromETH ? ETH_TOKEN_ADDRESS : sellToken,
 | 
			
		||||
                        isToETH ? ETH_TOKEN_ADDRESS : buyToken,
 | 
			
		||||
                        target,
 | 
			
		||||
                        fillData.poolAddress,
 | 
			
		||||
                        NULL_ADDRESS,
 | 
			
		||||
                        sellAmount,
 | 
			
		||||
                        minBuyAmount,
 | 
			
		||||
@@ -284,7 +302,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
            // ETH buy/sell is supported
 | 
			
		||||
            ![sellToken, buyToken].includes(NATIVE_FEE_TOKEN_BY_CHAIN_ID[ChainId.Mainnet])
 | 
			
		||||
        ) {
 | 
			
		||||
            const fillData = slippedOrders[0].fills[0].fillData as CurveFillData;
 | 
			
		||||
            const { fillData } = quote.hops[0].orders[0] as SwapQuoteCurveBridgeOrder;
 | 
			
		||||
            return {
 | 
			
		||||
                calldataHexString: this._exchangeProxy
 | 
			
		||||
                    .sellToLiquidityProvider(
 | 
			
		||||
@@ -295,8 +313,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
                        sellAmount,
 | 
			
		||||
                        minBuyAmount,
 | 
			
		||||
                        encodeCurveLiquidityProviderData({
 | 
			
		||||
                            curveAddress: fillData.pool.poolAddress,
 | 
			
		||||
                            exchangeFunctionSelector: fillData.pool.exchangeFunctionSelector,
 | 
			
		||||
                            curveAddress: fillData.poolAddress,
 | 
			
		||||
                            exchangeFunctionSelector: fillData.exchangeFunctionSelector,
 | 
			
		||||
                            fromCoinIdx: new BigNumber(fillData.fromTokenIdx),
 | 
			
		||||
                            toCoinIdx: new BigNumber(fillData.toTokenIdx),
 | 
			
		||||
                        }),
 | 
			
		||||
@@ -313,7 +331,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
            this.chainId === ChainId.Mainnet &&
 | 
			
		||||
            isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.Mooniswap])
 | 
			
		||||
        ) {
 | 
			
		||||
            const fillData = slippedOrders[0].fills[0].fillData as MooniswapFillData;
 | 
			
		||||
            const { fillData } = quote.hops[0].orders[0] as SwapQuoteMooniswapBridgeOrder;
 | 
			
		||||
            return {
 | 
			
		||||
                calldataHexString: this._exchangeProxy
 | 
			
		||||
                    .sellToLiquidityProvider(
 | 
			
		||||
@@ -323,7 +341,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
                        NULL_ADDRESS,
 | 
			
		||||
                        sellAmount,
 | 
			
		||||
                        minBuyAmount,
 | 
			
		||||
                        poolEncoder.encode([fillData.poolAddress]),
 | 
			
		||||
                        encodeAddress(fillData.poolAddress),
 | 
			
		||||
                    )
 | 
			
		||||
                    .getABIEncodedTransactionData(),
 | 
			
		||||
                ethAmount: isFromETH ? sellAmount : ZERO_AMOUNT,
 | 
			
		||||
@@ -336,7 +354,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
        if (this.chainId === ChainId.Mainnet && isMultiplexBatchFillCompatible(quote, optsWithDefaults)) {
 | 
			
		||||
            return {
 | 
			
		||||
                calldataHexString: this._encodeMultiplexBatchFillCalldata(
 | 
			
		||||
                    { ...quote, orders: slippedOrders },
 | 
			
		||||
                    quote.hops[0],
 | 
			
		||||
                    optsWithDefaults,
 | 
			
		||||
                ),
 | 
			
		||||
                ethAmount,
 | 
			
		||||
@@ -348,7 +366,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
        if (this.chainId === ChainId.Mainnet && isMultiplexMultiHopFillCompatible(quote, optsWithDefaults)) {
 | 
			
		||||
            return {
 | 
			
		||||
                calldataHexString: this._encodeMultiplexMultiHopFillCalldata(
 | 
			
		||||
                    { ...quote, orders: slippedOrders },
 | 
			
		||||
                    quote.hops,
 | 
			
		||||
                    optsWithDefaults,
 | 
			
		||||
                ),
 | 
			
		||||
                ethAmount,
 | 
			
		||||
@@ -371,47 +389,28 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If it's two hop we have an intermediate token this is needed to encode the individual FQT
 | 
			
		||||
        // and we also want to ensure no dust amount is left in the flash wallet
 | 
			
		||||
        const intermediateToken = quote.isTwoHop ? slippedOrders[0].makerToken : NULL_ADDRESS;
 | 
			
		||||
        // This transformer will fill the quote.
 | 
			
		||||
        if (quote.isTwoHop) {
 | 
			
		||||
            const [firstHopOrder, secondHopOrder] = slippedOrders;
 | 
			
		||||
        for (const [i, hop] of quote.hops.entries()) {
 | 
			
		||||
            let fillAmount = !isBuyQuote(quote)
 | 
			
		||||
                ? shouldSellEntireBalance ? MAX_UINT256 : hop.takerAmount
 | 
			
		||||
                : hop.makerAmount;
 | 
			
		||||
            let side = !isBuyQuote(quote) ? FillQuoteTransformerSide.Sell : FillQuoteTransformerSide.Buy;
 | 
			
		||||
            if (quote.hops.length > 1) { // Multi-hop.
 | 
			
		||||
                // Multi-hop is always a sell.
 | 
			
		||||
                side = FillQuoteTransformerSide.Sell;
 | 
			
		||||
                // Subsequent multi-hops always sell entire balance.
 | 
			
		||||
                fillAmount = i > 0 ? MAX_UINT256 : hop.takerAmount;
 | 
			
		||||
            }
 | 
			
		||||
            transforms.push({
 | 
			
		||||
                deploymentNonce: this.transformerNonces.fillQuoteTransformer,
 | 
			
		||||
                data: encodeFillQuoteTransformerData({
 | 
			
		||||
                    side: FillQuoteTransformerSide.Sell,
 | 
			
		||||
                    sellToken,
 | 
			
		||||
                    buyToken: intermediateToken,
 | 
			
		||||
                    ...getFQTTransformerDataFromOptimizedOrders([firstHopOrder]),
 | 
			
		||||
                    side,
 | 
			
		||||
                    fillAmount,
 | 
			
		||||
                    sellToken: hop.takerToken,
 | 
			
		||||
                    buyToken: hop.makerToken,
 | 
			
		||||
                    ...getFQTTransformerDataFromOptimizedOrders(hop.orders),
 | 
			
		||||
                    refundReceiver: refundReceiver || NULL_ADDRESS,
 | 
			
		||||
                    fillAmount: shouldSellEntireBalance ? MAX_UINT256 : firstHopOrder.takerAmount,
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
            transforms.push({
 | 
			
		||||
                deploymentNonce: this.transformerNonces.fillQuoteTransformer,
 | 
			
		||||
                data: encodeFillQuoteTransformerData({
 | 
			
		||||
                    side: FillQuoteTransformerSide.Sell,
 | 
			
		||||
                    buyToken,
 | 
			
		||||
                    sellToken: intermediateToken,
 | 
			
		||||
                    ...getFQTTransformerDataFromOptimizedOrders([secondHopOrder]),
 | 
			
		||||
                    refundReceiver: refundReceiver || NULL_ADDRESS,
 | 
			
		||||
                    fillAmount: MAX_UINT256,
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            const fillAmount = isBuyQuote(quote) ? quote.makerTokenFillAmount : quote.takerTokenFillAmount;
 | 
			
		||||
            transforms.push({
 | 
			
		||||
                deploymentNonce: this.transformerNonces.fillQuoteTransformer,
 | 
			
		||||
                data: encodeFillQuoteTransformerData({
 | 
			
		||||
                    side: isBuyQuote(quote) ? FillQuoteTransformerSide.Buy : FillQuoteTransformerSide.Sell,
 | 
			
		||||
                    sellToken,
 | 
			
		||||
                    buyToken,
 | 
			
		||||
                    ...getFQTTransformerDataFromOptimizedOrders(slippedOrders),
 | 
			
		||||
                    refundReceiver: refundReceiver || NULL_ADDRESS,
 | 
			
		||||
                    fillAmount: !isBuyQuote(quote) && shouldSellEntireBalance ? MAX_UINT256 : fillAmount,
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isToETH) {
 | 
			
		||||
@@ -475,10 +474,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
 | 
			
		||||
        // Return any unspent sell tokens.
 | 
			
		||||
        const payTakerTokens = [sellToken];
 | 
			
		||||
        // Return any unspent intermediate tokens for two-hop swaps.
 | 
			
		||||
        if (quote.isTwoHop) {
 | 
			
		||||
            payTakerTokens.push(intermediateToken);
 | 
			
		||||
        }
 | 
			
		||||
        // Return any unspent ETH. If ETH is the buy token, it will
 | 
			
		||||
        // be returned in TransformERC20Feature rather than PayTakerTransformer.
 | 
			
		||||
        if (!isToETH) {
 | 
			
		||||
@@ -519,9 +514,109 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
        throw new Error('Execution not supported for Exchange Proxy quotes');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private _encodeMultiplexBatchFillCalldata(quote: SwapQuote, opts: ExchangeProxyContractOpts): string {
 | 
			
		||||
    private _encodeMultiplexBatchFillCalldata(hop: SwapQuoteHop, opts: ExchangeProxyContractOpts): string {
 | 
			
		||||
        const subcalls = this._getMultiplexBatchSellSubcalls(hop.orders);
 | 
			
		||||
        if (opts.isFromETH) {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexBatchSellEthForToken(hop.makerToken, subcalls, hop.minMakerAmount)
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        } else if (opts.isToETH) {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexBatchSellTokenForEth(
 | 
			
		||||
                    hop.takerToken,
 | 
			
		||||
                    subcalls,
 | 
			
		||||
                    hop.maxTakerAmount,
 | 
			
		||||
                    hop.minMakerAmount,
 | 
			
		||||
                )
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        } else {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexBatchSellTokenForToken(
 | 
			
		||||
                    hop.takerToken,
 | 
			
		||||
                    hop.makerToken,
 | 
			
		||||
                    subcalls,
 | 
			
		||||
                    hop.maxTakerAmount,
 | 
			
		||||
                    hop.minMakerAmount,
 | 
			
		||||
                )
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private _encodeMultiplexMultiHopFillCalldata(hops: SwapQuoteHop[], opts: ExchangeProxyContractOpts): string {
 | 
			
		||||
        const subcalls = [];
 | 
			
		||||
        for_loop: for (const [i, order] of quote.orders.entries()) {
 | 
			
		||||
        for (const hop of hops) {
 | 
			
		||||
            if (hop.orders.length !== 1) {
 | 
			
		||||
                subcalls.push({
 | 
			
		||||
                    id: MultiplexSubcall.BatchSell,
 | 
			
		||||
                    sellAmount: hop.maxTakerAmount,
 | 
			
		||||
                    data: multiplexBatchSellEncoder.encode(this._getMultiplexBatchSellSubcalls(hop.orders)),
 | 
			
		||||
                });
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            const order = hop.orders[0] as SwapQuoteGenericBridgeOrder;
 | 
			
		||||
            switch (order.source) {
 | 
			
		||||
                case ERC20BridgeSource.UniswapV2:
 | 
			
		||||
                case ERC20BridgeSource.SushiSwap:
 | 
			
		||||
                    subcalls.push({
 | 
			
		||||
                        id: MultiplexSubcall.UniswapV2,
 | 
			
		||||
                        data: multiplexUniswapEncoder.encode({
 | 
			
		||||
                            tokens: (order as SwapQuoteUniswapV2BridgeOrder).fillData.tokenAddressPath,
 | 
			
		||||
                            isSushi: order.source === ERC20BridgeSource.SushiSwap,
 | 
			
		||||
                        }),
 | 
			
		||||
                    });
 | 
			
		||||
                    break;
 | 
			
		||||
                case ERC20BridgeSource.LiquidityProvider:
 | 
			
		||||
                    subcalls.push({
 | 
			
		||||
                        id: MultiplexSubcall.LiquidityProvider,
 | 
			
		||||
                        data: multiplexPlpEncoder.encode({
 | 
			
		||||
                            provider: (order as SwapQuoteLiquidityProviderBridgeOrder).fillData.poolAddress,
 | 
			
		||||
                            auxiliaryData: NULL_BYTES,
 | 
			
		||||
                        }),
 | 
			
		||||
                    });
 | 
			
		||||
                    break;
 | 
			
		||||
                case ERC20BridgeSource.UniswapV3:
 | 
			
		||||
                    subcalls.push({
 | 
			
		||||
                        id: MultiplexSubcall.UniswapV3,
 | 
			
		||||
                        data: (order as SwapQuoteUniswapV3BridgeOrder).fillData.encodedPath,
 | 
			
		||||
                    });
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    // Should never happen because we check `isMultiplexMultiHopFillCompatible`
 | 
			
		||||
                    // before calling this function.
 | 
			
		||||
                    throw new Error(`Multiplex multi-hop unsupported source: ${order.source}`);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        const tokenPath = getTokenPathFromHops(hops);
 | 
			
		||||
        const firstHop = hops[0];
 | 
			
		||||
        const lastHop = hops[hops.length - 1];
 | 
			
		||||
        if (opts.isFromETH) {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexMultiHopSellEthForToken(tokenPath, subcalls, lastHop.minMakerAmount)
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        } else if (opts.isToETH) {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexMultiHopSellTokenForEth(
 | 
			
		||||
                    tokenPath,
 | 
			
		||||
                    subcalls,
 | 
			
		||||
                    firstHop.maxTakerAmount,
 | 
			
		||||
                    lastHop.minMakerAmount,
 | 
			
		||||
                )
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        } else {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexMultiHopSellTokenForToken(
 | 
			
		||||
                    tokenPath,
 | 
			
		||||
                    subcalls,
 | 
			
		||||
                    firstHop.maxTakerAmount,
 | 
			
		||||
                    lastHop.minMakerAmount,
 | 
			
		||||
                )
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private _getMultiplexBatchSellSubcalls(orders: SwapQuoteOrder[]): any[] {
 | 
			
		||||
        const subcalls = [];
 | 
			
		||||
        for_loop: for (const [i, order] of orders.entries()) {
 | 
			
		||||
            switch_statement: switch (order.source) {
 | 
			
		||||
                case ERC20BridgeSource.Native:
 | 
			
		||||
                    if (order.type !== FillQuoteTransformerOrderType.Rfq) {
 | 
			
		||||
@@ -542,9 +637,9 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
                case ERC20BridgeSource.SushiSwap:
 | 
			
		||||
                    subcalls.push({
 | 
			
		||||
                        id: MultiplexSubcall.UniswapV2,
 | 
			
		||||
                        sellAmount: order.takerAmount,
 | 
			
		||||
                        sellAmount: (order as SwapQuoteUniswapV2BridgeOrder).maxTakerAmount,
 | 
			
		||||
                        data: multiplexUniswapEncoder.encode({
 | 
			
		||||
                            tokens: (order.fillData as UniswapV2FillData).tokenAddressPath,
 | 
			
		||||
                            tokens: (order as SwapQuoteUniswapV2BridgeOrder).fillData.tokenAddressPath,
 | 
			
		||||
                            isSushi: order.source === ERC20BridgeSource.SushiSwap,
 | 
			
		||||
                        }),
 | 
			
		||||
                    });
 | 
			
		||||
@@ -552,43 +647,46 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
                case ERC20BridgeSource.LiquidityProvider:
 | 
			
		||||
                    subcalls.push({
 | 
			
		||||
                        id: MultiplexSubcall.LiquidityProvider,
 | 
			
		||||
                        sellAmount: order.takerAmount,
 | 
			
		||||
                        sellAmount: (order as SwapQuoteLiquidityProviderBridgeOrder).maxTakerAmount,
 | 
			
		||||
                        data: multiplexPlpEncoder.encode({
 | 
			
		||||
                            provider: (order.fillData as LiquidityProviderFillData).poolAddress,
 | 
			
		||||
                            provider: (order as SwapQuoteLiquidityProviderBridgeOrder).fillData.poolAddress,
 | 
			
		||||
                            auxiliaryData: NULL_BYTES,
 | 
			
		||||
                        }),
 | 
			
		||||
                    });
 | 
			
		||||
                    break switch_statement;
 | 
			
		||||
                case ERC20BridgeSource.UniswapV3:
 | 
			
		||||
                    const fillData = (order as OptimizedMarketBridgeOrder<FinalUniswapV3FillData>).fillData;
 | 
			
		||||
                    subcalls.push({
 | 
			
		||||
                        id: MultiplexSubcall.UniswapV3,
 | 
			
		||||
                        sellAmount: order.takerAmount,
 | 
			
		||||
                        data: fillData.uniswapPath,
 | 
			
		||||
                        sellAmount: (order as SwapQuoteUniswapV3BridgeOrder).maxTakerAmount,
 | 
			
		||||
                        data: (order as SwapQuoteUniswapV3BridgeOrder).fillData.encodedPath,
 | 
			
		||||
                    });
 | 
			
		||||
                    break switch_statement;
 | 
			
		||||
                default:
 | 
			
		||||
                    const fqtData = encodeFillQuoteTransformerData({
 | 
			
		||||
                        side: FillQuoteTransformerSide.Sell,
 | 
			
		||||
                        sellToken: quote.takerToken,
 | 
			
		||||
                        buyToken: quote.makerToken,
 | 
			
		||||
                        ...getFQTTransformerDataFromOptimizedOrders(quote.orders.slice(i)),
 | 
			
		||||
                        sellToken: order.takerToken,
 | 
			
		||||
                        buyToken: order.makerToken,
 | 
			
		||||
                        ...getFQTTransformerDataFromOptimizedOrders(orders.slice(i)),
 | 
			
		||||
                        refundReceiver: NULL_ADDRESS,
 | 
			
		||||
                        fillAmount: MAX_UINT256,
 | 
			
		||||
                    });
 | 
			
		||||
                    const transformations = [
 | 
			
		||||
                        { deploymentNonce: this.transformerNonces.fillQuoteTransformer, data: fqtData },
 | 
			
		||||
                        {
 | 
			
		||||
                            deploymentNonce: this.transformerNonces.payTakerTransformer,
 | 
			
		||||
                            data: encodePayTakerTransformerData({
 | 
			
		||||
                                tokens: [quote.takerToken],
 | 
			
		||||
                                amounts: [],
 | 
			
		||||
                            }),
 | 
			
		||||
                        },
 | 
			
		||||
                        // TODO(lawrence): needed?
 | 
			
		||||
                        // {
 | 
			
		||||
                        //     deploymentNonce: this.transformerNonces.payTakerTransformer,
 | 
			
		||||
                        //     data: encodePayTakerTransformerData({
 | 
			
		||||
                        //         tokens: [hop.takerToken],
 | 
			
		||||
                        //         amounts: [],
 | 
			
		||||
                        //     }),
 | 
			
		||||
                        // },
 | 
			
		||||
                    ];
 | 
			
		||||
                    subcalls.push({
 | 
			
		||||
                        id: MultiplexSubcall.TransformERC20,
 | 
			
		||||
                        sellAmount: BigNumber.sum(...quote.orders.slice(i).map(o => o.takerAmount)),
 | 
			
		||||
                        sellAmount: BigNumber.sum(
 | 
			
		||||
                            ...orders.slice(i)
 | 
			
		||||
                                .map(o => (o as SwapQuoteGenericBridgeOrder).maxTakerAmount),
 | 
			
		||||
                        ),
 | 
			
		||||
                        data: multiplexTransformERC20Encoder.encode({
 | 
			
		||||
                            transformations,
 | 
			
		||||
                        }),
 | 
			
		||||
@@ -596,128 +694,21 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
                    break for_loop;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (opts.isFromETH) {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexBatchSellEthForToken(quote.makerToken, subcalls, quote.worstCaseQuoteInfo.makerAmount)
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        } else if (opts.isToETH) {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexBatchSellTokenForEth(
 | 
			
		||||
                    quote.takerToken,
 | 
			
		||||
                    subcalls,
 | 
			
		||||
                    quote.worstCaseQuoteInfo.totalTakerAmount,
 | 
			
		||||
                    quote.worstCaseQuoteInfo.makerAmount,
 | 
			
		||||
                )
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        } else {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexBatchSellTokenForToken(
 | 
			
		||||
                    quote.takerToken,
 | 
			
		||||
                    quote.makerToken,
 | 
			
		||||
                    subcalls,
 | 
			
		||||
                    quote.worstCaseQuoteInfo.totalTakerAmount,
 | 
			
		||||
                    quote.worstCaseQuoteInfo.makerAmount,
 | 
			
		||||
                )
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private _encodeMultiplexMultiHopFillCalldata(quote: SwapQuote, opts: ExchangeProxyContractOpts): string {
 | 
			
		||||
        const subcalls = [];
 | 
			
		||||
        const [firstHopOrder, secondHopOrder] = quote.orders;
 | 
			
		||||
        const intermediateToken = firstHopOrder.makerToken;
 | 
			
		||||
        const tokens = [quote.takerToken, intermediateToken, quote.makerToken];
 | 
			
		||||
 | 
			
		||||
        for (const order of [firstHopOrder, secondHopOrder]) {
 | 
			
		||||
            switch (order.source) {
 | 
			
		||||
                case ERC20BridgeSource.UniswapV2:
 | 
			
		||||
                case ERC20BridgeSource.SushiSwap:
 | 
			
		||||
                    subcalls.push({
 | 
			
		||||
                        id: MultiplexSubcall.UniswapV2,
 | 
			
		||||
                        data: multiplexUniswapEncoder.encode({
 | 
			
		||||
                            tokens: (order.fillData as UniswapV2FillData).tokenAddressPath,
 | 
			
		||||
                            isSushi: order.source === ERC20BridgeSource.SushiSwap,
 | 
			
		||||
                        }),
 | 
			
		||||
                    });
 | 
			
		||||
                    break;
 | 
			
		||||
                case ERC20BridgeSource.LiquidityProvider:
 | 
			
		||||
                    subcalls.push({
 | 
			
		||||
                        id: MultiplexSubcall.LiquidityProvider,
 | 
			
		||||
                        data: multiplexPlpEncoder.encode({
 | 
			
		||||
                            provider: (order.fillData as LiquidityProviderFillData).poolAddress,
 | 
			
		||||
                            auxiliaryData: NULL_BYTES,
 | 
			
		||||
                        }),
 | 
			
		||||
                    });
 | 
			
		||||
                    break;
 | 
			
		||||
                case ERC20BridgeSource.UniswapV3:
 | 
			
		||||
                    subcalls.push({
 | 
			
		||||
                        id: MultiplexSubcall.UniswapV3,
 | 
			
		||||
                        data: (order.fillData as FinalUniswapV3FillData).uniswapPath,
 | 
			
		||||
                    });
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    // Should never happen because we check `isMultiplexMultiHopFillCompatible`
 | 
			
		||||
                    // before calling this function.
 | 
			
		||||
                    throw new Error(`Multiplex multi-hop unsupported source: ${order.source}`);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (opts.isFromETH) {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexMultiHopSellEthForToken(tokens, subcalls, quote.worstCaseQuoteInfo.makerAmount)
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        } else if (opts.isToETH) {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexMultiHopSellTokenForEth(
 | 
			
		||||
                    tokens,
 | 
			
		||||
                    subcalls,
 | 
			
		||||
                    quote.worstCaseQuoteInfo.totalTakerAmount,
 | 
			
		||||
                    quote.worstCaseQuoteInfo.makerAmount,
 | 
			
		||||
                )
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        } else {
 | 
			
		||||
            return this._exchangeProxy
 | 
			
		||||
                .multiplexMultiHopSellTokenForToken(
 | 
			
		||||
                    tokens,
 | 
			
		||||
                    subcalls,
 | 
			
		||||
                    quote.worstCaseQuoteInfo.totalTakerAmount,
 | 
			
		||||
                    quote.worstCaseQuoteInfo.makerAmount,
 | 
			
		||||
                )
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        }
 | 
			
		||||
        return subcalls;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function slipNonNativeOrders(quote: MarketSellSwapQuote | MarketBuySwapQuote): OptimizedMarketOrder[] {
 | 
			
		||||
    const slippage = getMaxQuoteSlippageRate(quote);
 | 
			
		||||
    if (!slippage) {
 | 
			
		||||
        return quote.orders;
 | 
			
		||||
    }
 | 
			
		||||
    return quote.orders.map(o => {
 | 
			
		||||
        if (o.source === ERC20BridgeSource.Native) {
 | 
			
		||||
            return o;
 | 
			
		||||
function getTokenPathFromHops(hops: SwapQuoteHop[]): Address[] {
 | 
			
		||||
    const path = [];
 | 
			
		||||
    for (const [i, hop] of hops.entries()) {
 | 
			
		||||
        path.push(hop.takerToken);
 | 
			
		||||
        if (i === path.length - 1) {
 | 
			
		||||
            path.push(hop.makerToken);
 | 
			
		||||
        }
 | 
			
		||||
        return {
 | 
			
		||||
            ...o,
 | 
			
		||||
            ...(quote.type === MarketOperation.Sell
 | 
			
		||||
                ? { makerAmount: o.makerAmount.times(1 - slippage).integerValue(BigNumber.ROUND_DOWN) }
 | 
			
		||||
                : { takerAmount: o.takerAmount.times(1 + slippage).integerValue(BigNumber.ROUND_UP) }),
 | 
			
		||||
        };
 | 
			
		||||
    });
 | 
			
		||||
    }
 | 
			
		||||
    return path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getMaxQuoteSlippageRate(quote: MarketBuySwapQuote | MarketSellSwapQuote): number {
 | 
			
		||||
    if (quote.type === MarketOperation.Buy) {
 | 
			
		||||
        // (worstCaseTaker - bestCaseTaker) / bestCaseTaker
 | 
			
		||||
        // where worstCaseTaker >= bestCaseTaker
 | 
			
		||||
        return quote.worstCaseQuoteInfo.takerAmount
 | 
			
		||||
            .minus(quote.bestCaseQuoteInfo.takerAmount)
 | 
			
		||||
            .div(quote.bestCaseQuoteInfo.takerAmount)
 | 
			
		||||
            .toNumber();
 | 
			
		||||
    }
 | 
			
		||||
    // (bestCaseMaker - worstCaseMaker) / bestCaseMaker
 | 
			
		||||
    // where bestCaseMaker >= worstCaseMaker
 | 
			
		||||
    return quote.bestCaseQuoteInfo.makerAmount
 | 
			
		||||
        .minus(quote.worstCaseQuoteInfo.makerAmount)
 | 
			
		||||
        .div(quote.bestCaseQuoteInfo.makerAmount)
 | 
			
		||||
        .toNumber();
 | 
			
		||||
function encodeAddress(address: Address): Bytes {
 | 
			
		||||
    return hexUtils.leftPad(hexUtils.slice(address, 0, 20));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ export enum MultiplexSubcall {
 | 
			
		||||
    BatchSell,
 | 
			
		||||
    MultiHopSell,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const multiplexTransformERC20Encoder = AbiEncoder.create([
 | 
			
		||||
    {
 | 
			
		||||
        name: 'transformations',
 | 
			
		||||
@@ -22,15 +23,30 @@ export const multiplexTransformERC20Encoder = AbiEncoder.create([
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
export const multiplexRfqEncoder = AbiEncoder.create([
 | 
			
		||||
    { name: 'order', type: 'tuple', components: RfqOrder.STRUCT_ABI },
 | 
			
		||||
    { name: 'signature', type: 'tuple', components: SIGNATURE_ABI },
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
export const multiplexUniswapEncoder = AbiEncoder.create([
 | 
			
		||||
    { name: 'tokens', type: 'address[]' },
 | 
			
		||||
    { name: 'isSushi', type: 'bool' },
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
export const multiplexPlpEncoder = AbiEncoder.create([
 | 
			
		||||
    { name: 'provider', type: 'address' },
 | 
			
		||||
    { name: 'auxiliaryData', type: 'bytes' },
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
export const multiplexBatchSellEncoder = AbiEncoder.create([
 | 
			
		||||
    {
 | 
			
		||||
        name: 'subcalls',
 | 
			
		||||
        type: 'tuple[]',
 | 
			
		||||
        components: [
 | 
			
		||||
            { name: 'id', type: 'uint8' },
 | 
			
		||||
            { name: 'sellAmount', type: 'uint256' },
 | 
			
		||||
            { name: 'data', type: 'bytes' },
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
]);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,17 +2,17 @@ import { FillQuoteTransformerData, FillQuoteTransformerOrderType } from '@0x/pro
 | 
			
		||||
 | 
			
		||||
import { ExchangeProxyContractOpts, MarketBuySwapQuote, MarketOperation, SwapQuote } from '../types';
 | 
			
		||||
import {
 | 
			
		||||
    createBridgeDataForBridgeOrder,
 | 
			
		||||
    getErc20BridgeSourceToBridgeSource,
 | 
			
		||||
} from '../utils/market_operation_utils/orders';
 | 
			
		||||
import {
 | 
			
		||||
    ERC20BridgeSource,
 | 
			
		||||
    NativeLimitOrderFillData,
 | 
			
		||||
    NativeRfqOrderFillData,
 | 
			
		||||
    OptimizedMarketBridgeOrder,
 | 
			
		||||
    OptimizedMarketOrder,
 | 
			
		||||
    OptimizedMarketOrderBase,
 | 
			
		||||
} from '../utils/market_operation_utils/types';
 | 
			
		||||
import {
 | 
			
		||||
    SwapQuoteGenericBridgeOrder,
 | 
			
		||||
    SwapQuoteOrder,
 | 
			
		||||
    SwapQuoteLimitOrder,
 | 
			
		||||
    SwapQuoteRfqOrder,
 | 
			
		||||
} from '../types';
 | 
			
		||||
 | 
			
		||||
const MULTIPLEX_BATCH_FILL_SOURCES = [
 | 
			
		||||
    ERC20BridgeSource.UniswapV2,
 | 
			
		||||
@@ -29,16 +29,19 @@ export function isMultiplexBatchFillCompatible(quote: SwapQuote, opts: ExchangeP
 | 
			
		||||
    if (requiresTransformERC20(opts)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (quote.isTwoHop) {
 | 
			
		||||
    // Must not be multi-hop.
 | 
			
		||||
    if (quote.hops.length > 1) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (quote.orders.map(o => o.type).includes(FillQuoteTransformerOrderType.Limit)) {
 | 
			
		||||
    // Must not contain limit orders.
 | 
			
		||||
    const allOrderTypes = quote.hops.map(h => h.orders.map(o => o.type)).flat(2);
 | 
			
		||||
    if (allOrderTypes.includes(FillQuoteTransformerOrderType.Limit)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    // Use Multiplex if the non-fallback sources are a subset of
 | 
			
		||||
    // {UniswapV2, Sushiswap, RFQ, PLP, UniswapV3}
 | 
			
		||||
    const nonFallbackSources = Object.keys(quote.sourceBreakdown);
 | 
			
		||||
    return nonFallbackSources.every(source => MULTIPLEX_BATCH_FILL_SOURCES.includes(source as ERC20BridgeSource));
 | 
			
		||||
    const nonFallbackSources = quote.hops.map(h => h.orders.filter(o => !o.isFallback).map(o => o.source)).flat(2);
 | 
			
		||||
    return nonFallbackSources.every(s => MULTIPLEX_BATCH_FILL_SOURCES.includes(s));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MULTIPLEX_MULTIHOP_FILL_SOURCES = [
 | 
			
		||||
@@ -55,14 +58,12 @@ export function isMultiplexMultiHopFillCompatible(quote: SwapQuote, opts: Exchan
 | 
			
		||||
    if (requiresTransformERC20(opts)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (!quote.isTwoHop) {
 | 
			
		||||
    // Must be multi-hop.
 | 
			
		||||
    if (quote.hops.length < 2) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    const [firstHopOrder, secondHopOrder] = quote.orders;
 | 
			
		||||
    return (
 | 
			
		||||
        MULTIPLEX_MULTIHOP_FILL_SOURCES.includes(firstHopOrder.source) &&
 | 
			
		||||
        MULTIPLEX_MULTIHOP_FILL_SOURCES.includes(secondHopOrder.source)
 | 
			
		||||
    );
 | 
			
		||||
    const sources = quote.hops.map(h => h.orders.map(o => o.source)).flat(2);
 | 
			
		||||
    return sources.every(s => MULTIPLEX_MULTIHOP_FILL_SOURCES.includes(s));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -77,11 +78,11 @@ export function isDirectSwapCompatible(
 | 
			
		||||
    if (requiresTransformERC20(opts)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    // Must be a single order.
 | 
			
		||||
    if (quote.orders.length !== 1) {
 | 
			
		||||
    // Must be a single hop with a single order.
 | 
			
		||||
    if (quote.hops.length !== 1 || quote.hops[0].orders.length !== 1) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    const order = quote.orders[0];
 | 
			
		||||
    const order = quote.hops[0].orders[0];
 | 
			
		||||
    if (!directSources.includes(order.source)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -95,24 +96,24 @@ export function isBuyQuote(quote: SwapQuote): quote is MarketBuySwapQuote {
 | 
			
		||||
    return quote.type === MarketOperation.Buy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isOptimizedBridgeOrder(x: OptimizedMarketOrder): x is OptimizedMarketBridgeOrder {
 | 
			
		||||
function isBridgeOrder(x: SwapQuoteOrder): x is SwapQuoteGenericBridgeOrder {
 | 
			
		||||
    return x.type === FillQuoteTransformerOrderType.Bridge;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isOptimizedLimitOrder(x: OptimizedMarketOrder): x is OptimizedMarketOrderBase<NativeLimitOrderFillData> {
 | 
			
		||||
    return x.type === FillQuoteTransformerOrderType.Limit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isOptimizedRfqOrder(x: OptimizedMarketOrder): x is OptimizedMarketOrderBase<NativeRfqOrderFillData> {
 | 
			
		||||
    return x.type === FillQuoteTransformerOrderType.Rfq;
 | 
			
		||||
}
 | 
			
		||||
// function isOptimizedLimitOrder(x: OptimizedMarketOrder): x is OptimizedMarketOrderBase<NativeLimitOrderFillData> {
 | 
			
		||||
//     return x.type === FillQuoteTransformerOrderType.Limit;
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// function isOptimizedRfqOrder(x: OptimizedMarketOrder): x is OptimizedMarketOrderBase<NativeRfqOrderFillData> {
 | 
			
		||||
//     return x.type === FillQuoteTransformerOrderType.Rfq;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Converts the given `OptimizedMarketOrder`s into bridge, limit, and RFQ orders for
 | 
			
		||||
 * FillQuoteTransformer.
 | 
			
		||||
 */
 | 
			
		||||
export function getFQTTransformerDataFromOptimizedOrders(
 | 
			
		||||
    orders: OptimizedMarketOrder[],
 | 
			
		||||
    orders: SwapQuoteOrder[],
 | 
			
		||||
): Pick<FillQuoteTransformerData, 'bridgeOrders' | 'limitOrders' | 'rfqOrders' | 'fillSequence'> {
 | 
			
		||||
    const fqtData: Pick<FillQuoteTransformerData, 'bridgeOrders' | 'limitOrders' | 'rfqOrders' | 'fillSequence'> = {
 | 
			
		||||
        bridgeOrders: [],
 | 
			
		||||
@@ -122,25 +123,25 @@ export function getFQTTransformerDataFromOptimizedOrders(
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    for (const order of orders) {
 | 
			
		||||
        if (isOptimizedBridgeOrder(order)) {
 | 
			
		||||
        if (isBridgeOrder(order)) {
 | 
			
		||||
            fqtData.bridgeOrders.push({
 | 
			
		||||
                bridgeData: createBridgeDataForBridgeOrder(order),
 | 
			
		||||
                makerTokenAmount: order.makerAmount,
 | 
			
		||||
                takerTokenAmount: order.takerAmount,
 | 
			
		||||
                bridgeData: order.fillData.encodedFillData,
 | 
			
		||||
                makerTokenAmount: order.minMakerAmount,
 | 
			
		||||
                takerTokenAmount: order.maxTakerAmount,
 | 
			
		||||
                source: getErc20BridgeSourceToBridgeSource(order.source),
 | 
			
		||||
            });
 | 
			
		||||
        } else if (isOptimizedLimitOrder(order)) {
 | 
			
		||||
            fqtData.limitOrders.push({
 | 
			
		||||
                order: order.fillData.order,
 | 
			
		||||
                signature: order.fillData.signature,
 | 
			
		||||
                maxTakerTokenFillAmount: order.takerAmount,
 | 
			
		||||
            });
 | 
			
		||||
        } else if (isOptimizedRfqOrder(order)) {
 | 
			
		||||
            fqtData.rfqOrders.push({
 | 
			
		||||
                order: order.fillData.order,
 | 
			
		||||
                signature: order.fillData.signature,
 | 
			
		||||
                maxTakerTokenFillAmount: order.takerAmount,
 | 
			
		||||
            });
 | 
			
		||||
        // } else if (isOptimizedLimitOrder(order)) {
 | 
			
		||||
        //     fqtData.limitOrders.push({
 | 
			
		||||
        //         order: order.fillData.order,
 | 
			
		||||
        //         signature: order.fillData.signature,
 | 
			
		||||
        //         maxTakerTokenFillAmount: order.takerAmount,
 | 
			
		||||
        //     });
 | 
			
		||||
        // } else if (isOptimizedRfqOrder(order)) {
 | 
			
		||||
        //     fqtData.rfqOrders.push({
 | 
			
		||||
        //         order: order.fillData.order,
 | 
			
		||||
        //         signature: order.fillData.signature,
 | 
			
		||||
        //         maxTakerTokenFillAmount: order.takerAmount,
 | 
			
		||||
        //     });
 | 
			
		||||
        } else {
 | 
			
		||||
            // Should never happen
 | 
			
		||||
            throw new Error('Unknown Order type');
 | 
			
		||||
 
 | 
			
		||||
@@ -20,13 +20,12 @@ export class SwapQuoteConsumer implements SwapQuoteConsumerBase {
 | 
			
		||||
    private readonly _contractAddresses: ContractAddresses;
 | 
			
		||||
    private readonly _exchangeProxyConsumer: ExchangeProxySwapQuoteConsumer;
 | 
			
		||||
 | 
			
		||||
    public static getSwapQuoteConsumer(options: Partial<SwapQuoteConsumerOpts> = {}): SwapQuoteConsumer {
 | 
			
		||||
    public static getSwapQuoteConsumer(options: SwapQuoteConsumerOpts): SwapQuoteConsumer {
 | 
			
		||||
        return new SwapQuoteConsumer(options);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constructor(options: Partial<SwapQuoteConsumerOpts> = {}) {
 | 
			
		||||
        const { chainId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
 | 
			
		||||
        assert.isNumber('chainId', chainId);
 | 
			
		||||
    constructor(options: SwapQuoteConsumerOpts) {
 | 
			
		||||
        const { chainId } = options;
 | 
			
		||||
 | 
			
		||||
        this.chainId = chainId;
 | 
			
		||||
        this._contractAddresses = options.contractAddresses || getContractAddressesForChainOrThrow(chainId);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,15 @@
 | 
			
		||||
import { ChainId, getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
 | 
			
		||||
import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
 | 
			
		||||
import { FillQuoteTransformerOrderType, LimitOrder } from '@0x/protocol-utils';
 | 
			
		||||
import { BigNumber, providerUtils } from '@0x/utils';
 | 
			
		||||
import Axios, { AxiosInstance } from 'axios';
 | 
			
		||||
import { BlockParamLiteral, MethodAbi, SupportedProvider, ZeroExProvider } from 'ethereum-types';
 | 
			
		||||
import { FastABI } from 'fast-abi';
 | 
			
		||||
import { SupportedProvider, ZeroExProvider } from 'ethereum-types';
 | 
			
		||||
import { Agent as HttpAgent } from 'http';
 | 
			
		||||
import { Agent as HttpsAgent } from 'https';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
import { constants, INVALID_SIGNATURE, KEEP_ALIVE_TTL } from './constants';
 | 
			
		||||
import {
 | 
			
		||||
    Address,
 | 
			
		||||
    AssetSwapperContractAddresses,
 | 
			
		||||
    MarketBuySwapQuote,
 | 
			
		||||
    MarketOperation,
 | 
			
		||||
@@ -19,6 +18,10 @@ import {
 | 
			
		||||
    SignedNativeOrder,
 | 
			
		||||
    SwapQuote,
 | 
			
		||||
    SwapQuoteInfo,
 | 
			
		||||
    SwapQuoteHop,
 | 
			
		||||
    SwapQuoteOrder,
 | 
			
		||||
    SwapQuoteGenericBridgeOrder,
 | 
			
		||||
    SwapQuoteNativeOrder,
 | 
			
		||||
    SwapQuoteOrdersBreakdown,
 | 
			
		||||
    SwapQuoteRequestOpts,
 | 
			
		||||
    SwapQuoterOpts,
 | 
			
		||||
@@ -26,25 +29,26 @@ import {
 | 
			
		||||
} from './types';
 | 
			
		||||
import { assert } from './utils/assert';
 | 
			
		||||
import { MarketOperationUtils } from './utils/market_operation_utils';
 | 
			
		||||
import { BancorService } from './utils/market_operation_utils/bancor_service';
 | 
			
		||||
import { SAMPLER_ADDRESS, SOURCE_FLAGS, ZERO_AMOUNT } from './utils/market_operation_utils/constants';
 | 
			
		||||
import { DexOrderSampler } from './utils/market_operation_utils/sampler';
 | 
			
		||||
import { ZERO_AMOUNT } from './utils/market_operation_utils/constants';
 | 
			
		||||
import { SamplerClient } from './utils/market_operation_utils/sampler';
 | 
			
		||||
import { SourceFilters } from './utils/market_operation_utils/source_filters';
 | 
			
		||||
import {
 | 
			
		||||
    ERC20BridgeSource,
 | 
			
		||||
    FeeSchedule,
 | 
			
		||||
    FillData,
 | 
			
		||||
    GetMarketOrdersOpts,
 | 
			
		||||
    MarketDepth,
 | 
			
		||||
    MarketDepthSide,
 | 
			
		||||
    MarketSideLiquidity,
 | 
			
		||||
    OptimizedMarketOrder,
 | 
			
		||||
    OptimizedHop,
 | 
			
		||||
    OptimizedOrder,
 | 
			
		||||
    OptimizedBridgeOrder,
 | 
			
		||||
    OptimizedLimitOrder,
 | 
			
		||||
    OptimizedRfqOrder,
 | 
			
		||||
    OptimizedGenericBridgeOrder,
 | 
			
		||||
    OptimizerResultWithReport,
 | 
			
		||||
} from './utils/market_operation_utils/types';
 | 
			
		||||
import { ProtocolFeeUtils } from './utils/protocol_fee_utils';
 | 
			
		||||
import { QuoteRequestor } from './utils/quote_requestor';
 | 
			
		||||
import { QuoteFillResult, simulateBestCaseFill, simulateWorstCaseFill } from './utils/quote_simulation';
 | 
			
		||||
import { ERC20BridgeSamplerContract } from './wrappers';
 | 
			
		||||
 | 
			
		||||
export abstract class Orderbook {
 | 
			
		||||
    public abstract getOrdersAsync(
 | 
			
		||||
@@ -85,20 +89,15 @@ export class SwapQuoter {
 | 
			
		||||
     *
 | 
			
		||||
     * @return  An instance of SwapQuoter
 | 
			
		||||
     */
 | 
			
		||||
    constructor(supportedProvider: SupportedProvider, orderbook: Orderbook, options: Partial<SwapQuoterOpts> = {}) {
 | 
			
		||||
    constructor(supportedProvider: SupportedProvider, orderbook: Orderbook, options: SwapQuoterOpts) {
 | 
			
		||||
        const {
 | 
			
		||||
            chainId,
 | 
			
		||||
            expiryBufferMs,
 | 
			
		||||
            permittedOrderFeeTypes,
 | 
			
		||||
            samplerGasLimit,
 | 
			
		||||
            rfqt,
 | 
			
		||||
            tokenAdjacencyGraph,
 | 
			
		||||
            liquidityProviderRegistry,
 | 
			
		||||
        } = { ...constants.DEFAULT_SWAP_QUOTER_OPTS, ...options };
 | 
			
		||||
        } = options;
 | 
			
		||||
        const provider = providerUtils.standardizeOrThrow(supportedProvider);
 | 
			
		||||
        assert.isValidOrderbook('orderbook', orderbook);
 | 
			
		||||
        assert.isNumber('chainId', chainId);
 | 
			
		||||
        assert.isNumber('expiryBufferMs', expiryBufferMs);
 | 
			
		||||
        this.chainId = chainId;
 | 
			
		||||
        this.provider = provider;
 | 
			
		||||
        this.orderbook = orderbook;
 | 
			
		||||
@@ -113,45 +112,11 @@ export class SwapQuoter {
 | 
			
		||||
            constants.PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS,
 | 
			
		||||
            options.ethGasStationUrl,
 | 
			
		||||
        );
 | 
			
		||||
        // Allow the sampler bytecode to be overwritten using geths override functionality
 | 
			
		||||
        const samplerBytecode = _.get(artifacts.ERC20BridgeSampler, 'compilerOutput.evm.deployedBytecode.object');
 | 
			
		||||
        // Allow address of the Sampler to be overridden, i.e in Ganache where overrides do not work
 | 
			
		||||
        const samplerAddress = (options.samplerOverrides && options.samplerOverrides.to) || SAMPLER_ADDRESS;
 | 
			
		||||
        const defaultCodeOverrides = samplerBytecode
 | 
			
		||||
            ? {
 | 
			
		||||
                  [samplerAddress]: { code: samplerBytecode },
 | 
			
		||||
              }
 | 
			
		||||
            : {};
 | 
			
		||||
        const samplerOverrides = _.assign(
 | 
			
		||||
            { block: BlockParamLiteral.Latest, overrides: defaultCodeOverrides },
 | 
			
		||||
            options.samplerOverrides,
 | 
			
		||||
        );
 | 
			
		||||
        const fastAbi = new FastABI(ERC20BridgeSamplerContract.ABI() as MethodAbi[], { BigNumber });
 | 
			
		||||
        const samplerContract = new ERC20BridgeSamplerContract(
 | 
			
		||||
            samplerAddress,
 | 
			
		||||
            this.provider,
 | 
			
		||||
            {
 | 
			
		||||
                gas: samplerGasLimit,
 | 
			
		||||
            },
 | 
			
		||||
            {},
 | 
			
		||||
            undefined,
 | 
			
		||||
            {
 | 
			
		||||
                encodeInput: (fnName: string, values: any) => fastAbi.encodeInput(fnName, values),
 | 
			
		||||
                decodeOutput: (fnName: string, data: string) => fastAbi.decodeOutput(fnName, data),
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        this._marketOperationUtils = new MarketOperationUtils(
 | 
			
		||||
            new DexOrderSampler(
 | 
			
		||||
            SamplerClient.createFromChainIdAndEndpoint(
 | 
			
		||||
                this.chainId,
 | 
			
		||||
                samplerContract,
 | 
			
		||||
                samplerOverrides,
 | 
			
		||||
                undefined, // pools caches for balancer and cream
 | 
			
		||||
                tokenAdjacencyGraph,
 | 
			
		||||
                liquidityProviderRegistry,
 | 
			
		||||
                this.chainId === ChainId.Mainnet // Enable Bancor only on Mainnet
 | 
			
		||||
                    ? async () => BancorService.createAsync(provider)
 | 
			
		||||
                    : async () => undefined,
 | 
			
		||||
                options.samplerServiceUrl,
 | 
			
		||||
            ),
 | 
			
		||||
            this._contractAddresses,
 | 
			
		||||
            {
 | 
			
		||||
@@ -216,7 +181,6 @@ export class SwapQuoter {
 | 
			
		||||
                        MarketOperation.Buy,
 | 
			
		||||
                        makerTokenBuyAmounts[i],
 | 
			
		||||
                        gasPrice,
 | 
			
		||||
                        opts.gasSchedule,
 | 
			
		||||
                        opts.bridgeSlippage,
 | 
			
		||||
                    );
 | 
			
		||||
                } else {
 | 
			
		||||
@@ -243,49 +207,50 @@ export class SwapQuoter {
 | 
			
		||||
        takerAssetAmount: BigNumber,
 | 
			
		||||
        options: Partial<SwapQuoteRequestOpts> = {},
 | 
			
		||||
    ): Promise<MarketDepth> {
 | 
			
		||||
        assert.isString('makerToken', makerToken);
 | 
			
		||||
        assert.isString('takerToken', takerToken);
 | 
			
		||||
        const sourceFilters = new SourceFilters([], options.excludedSources, options.includedSources);
 | 
			
		||||
 | 
			
		||||
        let [sellOrders, buyOrders] = !sourceFilters.isAllowed(ERC20BridgeSource.Native)
 | 
			
		||||
            ? [[], []]
 | 
			
		||||
            : await Promise.all([
 | 
			
		||||
                  this.orderbook.getOrdersAsync(makerToken, takerToken),
 | 
			
		||||
                  this.orderbook.getOrdersAsync(takerToken, makerToken),
 | 
			
		||||
              ]);
 | 
			
		||||
        if (!sellOrders || sellOrders.length === 0) {
 | 
			
		||||
            sellOrders = [createDummyOrder(makerToken, takerToken)];
 | 
			
		||||
        }
 | 
			
		||||
        if (!buyOrders || buyOrders.length === 0) {
 | 
			
		||||
            buyOrders = [createDummyOrder(takerToken, makerToken)];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const getMarketDepthSide = (marketSideLiquidity: MarketSideLiquidity): MarketDepthSide => {
 | 
			
		||||
            const { dexQuotes, nativeOrders } = marketSideLiquidity.quotes;
 | 
			
		||||
            const { side } = marketSideLiquidity;
 | 
			
		||||
 | 
			
		||||
            return [
 | 
			
		||||
                ...dexQuotes,
 | 
			
		||||
                nativeOrders.map(o => {
 | 
			
		||||
                    return {
 | 
			
		||||
                        input: side === MarketOperation.Sell ? o.fillableTakerAmount : o.fillableMakerAmount,
 | 
			
		||||
                        output: side === MarketOperation.Sell ? o.fillableMakerAmount : o.fillableTakerAmount,
 | 
			
		||||
                        fillData: o,
 | 
			
		||||
                        source: ERC20BridgeSource.Native,
 | 
			
		||||
                    };
 | 
			
		||||
                }),
 | 
			
		||||
            ];
 | 
			
		||||
        };
 | 
			
		||||
        const [bids, asks] = await Promise.all([
 | 
			
		||||
            this._marketOperationUtils.getMarketBuyLiquidityAsync(buyOrders, takerAssetAmount, options),
 | 
			
		||||
            this._marketOperationUtils.getMarketSellLiquidityAsync(sellOrders, takerAssetAmount, options),
 | 
			
		||||
        ]);
 | 
			
		||||
        return {
 | 
			
		||||
            bids: getMarketDepthSide(bids),
 | 
			
		||||
            asks: getMarketDepthSide(asks),
 | 
			
		||||
            makerTokenDecimals: asks.makerTokenDecimals,
 | 
			
		||||
            takerTokenDecimals: asks.takerTokenDecimals,
 | 
			
		||||
        };
 | 
			
		||||
        throw new Error(`Not implemented`);
 | 
			
		||||
        // assert.isString('makerToken', makerToken);
 | 
			
		||||
        // assert.isString('takerToken', takerToken);
 | 
			
		||||
        // const sourceFilters = new SourceFilters([], options.excludedSources, options.includedSources);
 | 
			
		||||
        //
 | 
			
		||||
        // let [sellOrders, buyOrders] = !sourceFilters.isAllowed(ERC20BridgeSource.Native)
 | 
			
		||||
        //     ? [[], []]
 | 
			
		||||
        //     : await Promise.all([
 | 
			
		||||
        //           this.orderbook.getOrdersAsync(makerToken, takerToken),
 | 
			
		||||
        //           this.orderbook.getOrdersAsync(takerToken, makerToken),
 | 
			
		||||
        //       ]);
 | 
			
		||||
        // if (!sellOrders || sellOrders.length === 0) {
 | 
			
		||||
        //     sellOrders = [createDummyOrder(makerToken, takerToken)];
 | 
			
		||||
        // }
 | 
			
		||||
        // if (!buyOrders || buyOrders.length === 0) {
 | 
			
		||||
        //     buyOrders = [createDummyOrder(takerToken, makerToken)];
 | 
			
		||||
        // }
 | 
			
		||||
        //
 | 
			
		||||
        // const getMarketDepthSide = (marketSideLiquidity: MarketSideLiquidity): MarketDepthSide => {
 | 
			
		||||
        //     const { dexQuotes, nativeOrders } = marketSideLiquidity.quotes;
 | 
			
		||||
        //     const { side } = marketSideLiquidity;
 | 
			
		||||
        //
 | 
			
		||||
        //     return [
 | 
			
		||||
        //         ...dexQuotes,
 | 
			
		||||
        //         nativeOrders.map(o => {
 | 
			
		||||
        //             return {
 | 
			
		||||
        //                 input: side === MarketOperation.Sell ? o.fillableTakerAmount : o.fillableMakerAmount,
 | 
			
		||||
        //                 output: side === MarketOperation.Sell ? o.fillableMakerAmount : o.fillableTakerAmount,
 | 
			
		||||
        //                 fillData: o,
 | 
			
		||||
        //                 source: ERC20BridgeSource.Native,
 | 
			
		||||
        //             };
 | 
			
		||||
        //         }),
 | 
			
		||||
        //     ];
 | 
			
		||||
        // };
 | 
			
		||||
        // const [bids, asks] = await Promise.all([
 | 
			
		||||
        //     this._marketOperationUtils.getMarketBuyLiquidityAsync(buyOrders, takerAssetAmount, options),
 | 
			
		||||
        //     this._marketOperationUtils.getMarketSellLiquidityAsync(sellOrders, takerAssetAmount, options),
 | 
			
		||||
        // ]);
 | 
			
		||||
        // return {
 | 
			
		||||
        //     bids: getMarketDepthSide(bids),
 | 
			
		||||
        //     asks: getMarketDepthSide(asks),
 | 
			
		||||
        //     makerTokenDecimals: asks.makerTokenDecimals,
 | 
			
		||||
        //     takerTokenDecimals: asks.takerTokenDecimals,
 | 
			
		||||
        // };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -364,9 +329,6 @@ export class SwapQuoter {
 | 
			
		||||
        const calcOpts: GetMarketOrdersOpts = {
 | 
			
		||||
            ...cloneOpts,
 | 
			
		||||
            gasPrice,
 | 
			
		||||
            feeSchedule: _.mapValues(opts.feeSchedule, gasCost => (fillData: FillData) =>
 | 
			
		||||
                gasCost === undefined ? 0 : gasPrice.times(gasCost(fillData)),
 | 
			
		||||
            ),
 | 
			
		||||
            exchangeProxyOverhead: flags => gasPrice.times(opts.exchangeProxyOverhead(flags)),
 | 
			
		||||
        };
 | 
			
		||||
        // pass the QuoteRequestor on if rfqt enabled
 | 
			
		||||
@@ -397,12 +359,13 @@ export class SwapQuoter {
 | 
			
		||||
            marketOperation,
 | 
			
		||||
            assetFillAmount,
 | 
			
		||||
            gasPrice,
 | 
			
		||||
            opts.gasSchedule,
 | 
			
		||||
            opts.bridgeSlippage,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Use the raw gas, not scaled by gas price
 | 
			
		||||
        const exchangeProxyOverhead = opts.exchangeProxyOverhead(result.sourceFlags).toNumber();
 | 
			
		||||
        const exchangeProxyOverhead = BigNumber.sum(
 | 
			
		||||
            ...result.hops.map(h => opts.exchangeProxyOverhead(h.sourceFlags)),
 | 
			
		||||
        ).toNumber();
 | 
			
		||||
        swapQuote.bestCaseQuoteInfo.gas += exchangeProxyOverhead;
 | 
			
		||||
        swapQuote.worstCaseQuoteInfo.gas += exchangeProxyOverhead;
 | 
			
		||||
 | 
			
		||||
@@ -496,26 +459,22 @@ function createSwapQuote(
 | 
			
		||||
    optimizerResult: OptimizerResultWithReport,
 | 
			
		||||
    makerToken: string,
 | 
			
		||||
    takerToken: string,
 | 
			
		||||
    operation: MarketOperation,
 | 
			
		||||
    side: MarketOperation,
 | 
			
		||||
    assetFillAmount: BigNumber,
 | 
			
		||||
    gasPrice: BigNumber,
 | 
			
		||||
    gasSchedule: FeeSchedule,
 | 
			
		||||
    slippage: number,
 | 
			
		||||
): SwapQuote {
 | 
			
		||||
    const {
 | 
			
		||||
        optimizedOrders,
 | 
			
		||||
        hops,
 | 
			
		||||
        quoteReport,
 | 
			
		||||
        sourceFlags,
 | 
			
		||||
        takerAmountPerEth,
 | 
			
		||||
        makerAmountPerEth,
 | 
			
		||||
        priceComparisonsReport,
 | 
			
		||||
    } = optimizerResult;
 | 
			
		||||
    const isTwoHop = sourceFlags === SOURCE_FLAGS[ERC20BridgeSource.MultiHop];
 | 
			
		||||
 | 
			
		||||
    // Calculate quote info
 | 
			
		||||
    const { bestCaseQuoteInfo, worstCaseQuoteInfo, sourceBreakdown } = isTwoHop
 | 
			
		||||
        ? calculateTwoHopQuoteInfo(optimizedOrders, operation, gasSchedule, slippage)
 | 
			
		||||
        : calculateQuoteInfo(optimizedOrders, operation, assetFillAmount, gasPrice, gasSchedule, slippage);
 | 
			
		||||
    const quoteHops = hops.map(hop => toSwapQuoteHop(hop, side, slippage));
 | 
			
		||||
    const { bestCaseQuoteInfo, worstCaseQuoteInfo, sourceBreakdown } =
 | 
			
		||||
        calculateQuoteInfo(quoteHops, side, assetFillAmount, gasPrice, slippage);
 | 
			
		||||
 | 
			
		||||
    // Put together the swap quote
 | 
			
		||||
    const { makerTokenDecimals, takerTokenDecimals } = optimizerResult.marketSideLiquidity;
 | 
			
		||||
@@ -523,7 +482,7 @@ function createSwapQuote(
 | 
			
		||||
        makerToken,
 | 
			
		||||
        takerToken,
 | 
			
		||||
        gasPrice,
 | 
			
		||||
        orders: optimizedOrders,
 | 
			
		||||
        orders: hops.map(h => h.orders).flat(1),
 | 
			
		||||
        bestCaseQuoteInfo,
 | 
			
		||||
        worstCaseQuoteInfo,
 | 
			
		||||
        sourceBreakdown,
 | 
			
		||||
@@ -532,116 +491,216 @@ function createSwapQuote(
 | 
			
		||||
        takerAmountPerEth,
 | 
			
		||||
        makerAmountPerEth,
 | 
			
		||||
        quoteReport,
 | 
			
		||||
        isTwoHop,
 | 
			
		||||
        priceComparisonsReport,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (operation === MarketOperation.Buy) {
 | 
			
		||||
    if (side === MarketOperation.Buy) {
 | 
			
		||||
        return {
 | 
			
		||||
            ...swapQuote,
 | 
			
		||||
            type: MarketOperation.Buy,
 | 
			
		||||
            makerTokenFillAmount: assetFillAmount,
 | 
			
		||||
            maxSlippage: slippage,
 | 
			
		||||
            hops: quoteHops,
 | 
			
		||||
        };
 | 
			
		||||
    } else {
 | 
			
		||||
        return {
 | 
			
		||||
            ...swapQuote,
 | 
			
		||||
            type: MarketOperation.Sell,
 | 
			
		||||
            takerTokenFillAmount: assetFillAmount,
 | 
			
		||||
            maxSlippage: slippage,
 | 
			
		||||
            hops: quoteHops,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function toSwapQuoteHop(hop: OptimizedHop, side: MarketOperation, slippage: number): SwapQuoteHop {
 | 
			
		||||
    const orders = hop.orders.map(o => toSwapQuoteOrder(o, side, slippage));
 | 
			
		||||
    const takerAmount = side === MarketOperation.Sell ? hop.inputAmount : hop.outputAmount;
 | 
			
		||||
    const makerAmount = side === MarketOperation.Sell ? hop.outputAmount : hop.inputAmount;
 | 
			
		||||
    return {
 | 
			
		||||
        orders,
 | 
			
		||||
        makerAmount: roundMakerAmount(side, makerAmount),
 | 
			
		||||
        takerAmount: roundTakerAmount(side, takerAmount),
 | 
			
		||||
        makerToken: side === MarketOperation.Sell ? hop.outputToken : hop.inputToken,
 | 
			
		||||
        takerToken: side === MarketOperation.Sell ? hop.inputToken : hop.outputToken,
 | 
			
		||||
        minMakerAmount: slipMakerAmount(side, makerAmount, slippage),
 | 
			
		||||
        maxTakerAmount: slipTakerAmount(side, takerAmount, slippage),
 | 
			
		||||
        sourceFlags: hop.sourceFlags,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function roundMakerAmount(side: MarketOperation, makerAmount: BigNumber): BigNumber {
 | 
			
		||||
    const rm = side === MarketOperation.Sell ? BigNumber.ROUND_DOWN : BigNumber.ROUND_UP;
 | 
			
		||||
    return makerAmount.integerValue(rm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function roundTakerAmount(side: MarketOperation, takerAmount: BigNumber): BigNumber {
 | 
			
		||||
    const rm = side === MarketOperation.Sell ? BigNumber.ROUND_UP : BigNumber.ROUND_UP;
 | 
			
		||||
    return takerAmount.integerValue(rm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function slipMakerAmount(side: MarketOperation, makerAmount: BigNumber, slippage: number): BigNumber {
 | 
			
		||||
    return roundMakerAmount(
 | 
			
		||||
        side,
 | 
			
		||||
        side === MarketOperation.Sell ? makerAmount.times(1 - slippage) : makerAmount,
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function slipTakerAmount(side: MarketOperation, takerAmount: BigNumber, slippage: number): BigNumber {
 | 
			
		||||
    return roundTakerAmount(
 | 
			
		||||
        side,
 | 
			
		||||
        side === MarketOperation.Sell ? takerAmount : takerAmount.times(1 + slippage),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function toSwapQuoteOrder(order: OptimizedOrder, side: MarketOperation, slippage: number): SwapQuoteGenericBridgeOrder | SwapQuoteNativeOrder {
 | 
			
		||||
    const { inputToken, outputToken, inputAmount, outputAmount, ...rest } = order;
 | 
			
		||||
    const common = {
 | 
			
		||||
        ...rest,
 | 
			
		||||
        takerToken: side === MarketOperation.Sell ? inputToken : outputToken,
 | 
			
		||||
        makerToken: side === MarketOperation.Sell ? outputToken : inputToken,
 | 
			
		||||
        takerAmount: side === MarketOperation.Sell ? inputAmount : outputAmount,
 | 
			
		||||
        makerAmount: side === MarketOperation.Sell ? outputAmount : inputAmount,
 | 
			
		||||
    };
 | 
			
		||||
    if (isBridgeOrder(order)) {
 | 
			
		||||
        return {
 | 
			
		||||
            ...common,
 | 
			
		||||
            minMakerAmount: slipMakerAmount(
 | 
			
		||||
                side,
 | 
			
		||||
                side === MarketOperation.Sell
 | 
			
		||||
                    ? order.outputAmount
 | 
			
		||||
                    : order.inputAmount,
 | 
			
		||||
                slippage,
 | 
			
		||||
            ),
 | 
			
		||||
            maxTakerAmount: slipTakerAmount(
 | 
			
		||||
                side,
 | 
			
		||||
                side === MarketOperation.Sell
 | 
			
		||||
                    ? order.inputAmount
 | 
			
		||||
                    : order.outputAmount,
 | 
			
		||||
                slippage,
 | 
			
		||||
            ),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
    return common as SwapQuoteNativeOrder;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isBridgeOrder(order: OptimizedOrder): order is OptimizedGenericBridgeOrder {
 | 
			
		||||
    return order.type === FillQuoteTransformerOrderType.Bridge;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function calculateQuoteInfo(
 | 
			
		||||
    optimizedOrders: OptimizedMarketOrder[],
 | 
			
		||||
    operation: MarketOperation,
 | 
			
		||||
    assetFillAmount: BigNumber,
 | 
			
		||||
    hops: SwapQuoteHop[],
 | 
			
		||||
    side: MarketOperation,
 | 
			
		||||
    fillAmount: BigNumber,
 | 
			
		||||
    gasPrice: BigNumber,
 | 
			
		||||
    gasSchedule: FeeSchedule,
 | 
			
		||||
    slippage: number,
 | 
			
		||||
): { bestCaseQuoteInfo: SwapQuoteInfo; worstCaseQuoteInfo: SwapQuoteInfo; sourceBreakdown: SwapQuoteOrdersBreakdown } {
 | 
			
		||||
    const bestCaseFillResult = simulateBestCaseFill({
 | 
			
		||||
        gasPrice,
 | 
			
		||||
        orders: optimizedOrders,
 | 
			
		||||
        side: operation,
 | 
			
		||||
        fillAmount: assetFillAmount,
 | 
			
		||||
        opts: { gasSchedule },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const worstCaseFillResult = simulateWorstCaseFill({
 | 
			
		||||
        gasPrice,
 | 
			
		||||
        orders: optimizedOrders,
 | 
			
		||||
        side: operation,
 | 
			
		||||
        fillAmount: assetFillAmount,
 | 
			
		||||
        opts: { gasSchedule, slippage },
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        bestCaseQuoteInfo: fillResultsToQuoteInfo(bestCaseFillResult),
 | 
			
		||||
        worstCaseQuoteInfo: fillResultsToQuoteInfo(worstCaseFillResult),
 | 
			
		||||
        sourceBreakdown: getSwapQuoteOrdersBreakdown(bestCaseFillResult.fillAmountBySource),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function calculateTwoHopQuoteInfo(
 | 
			
		||||
    optimizedOrders: OptimizedMarketOrder[],
 | 
			
		||||
    operation: MarketOperation,
 | 
			
		||||
    gasSchedule: FeeSchedule,
 | 
			
		||||
    slippage: number,
 | 
			
		||||
): { bestCaseQuoteInfo: SwapQuoteInfo; worstCaseQuoteInfo: SwapQuoteInfo; sourceBreakdown: SwapQuoteOrdersBreakdown } {
 | 
			
		||||
    const [firstHopOrder, secondHopOrder] = optimizedOrders;
 | 
			
		||||
    const [firstHopFill] = firstHopOrder.fills;
 | 
			
		||||
    const [secondHopFill] = secondHopOrder.fills;
 | 
			
		||||
    const gas = new BigNumber(
 | 
			
		||||
        gasSchedule[ERC20BridgeSource.MultiHop]!({
 | 
			
		||||
            firstHopSource: _.pick(firstHopFill, 'source', 'fillData'),
 | 
			
		||||
            secondHopSource: _.pick(secondHopFill, 'source', 'fillData'),
 | 
			
		||||
        }),
 | 
			
		||||
    ).toNumber();
 | 
			
		||||
    return {
 | 
			
		||||
        bestCaseQuoteInfo: {
 | 
			
		||||
            makerAmount: operation === MarketOperation.Sell ? secondHopFill.output : secondHopFill.input,
 | 
			
		||||
            takerAmount: operation === MarketOperation.Sell ? firstHopFill.input : firstHopFill.output,
 | 
			
		||||
            totalTakerAmount: operation === MarketOperation.Sell ? firstHopFill.input : firstHopFill.output,
 | 
			
		||||
            feeTakerTokenAmount: constants.ZERO_AMOUNT,
 | 
			
		||||
            protocolFeeInWeiAmount: constants.ZERO_AMOUNT,
 | 
			
		||||
            gas,
 | 
			
		||||
        },
 | 
			
		||||
        // TODO jacob consolidate this with quote simulation worstCase
 | 
			
		||||
        worstCaseQuoteInfo: {
 | 
			
		||||
            makerAmount: MarketOperation.Sell
 | 
			
		||||
                ? secondHopOrder.makerAmount.times(1 - slippage).integerValue()
 | 
			
		||||
                : secondHopOrder.makerAmount,
 | 
			
		||||
            takerAmount: MarketOperation.Sell
 | 
			
		||||
                ? firstHopOrder.takerAmount
 | 
			
		||||
                : firstHopOrder.takerAmount.times(1 + slippage).integerValue(),
 | 
			
		||||
            totalTakerAmount: MarketOperation.Sell
 | 
			
		||||
                ? firstHopOrder.takerAmount
 | 
			
		||||
                : firstHopOrder.takerAmount.times(1 + slippage).integerValue(),
 | 
			
		||||
            feeTakerTokenAmount: constants.ZERO_AMOUNT,
 | 
			
		||||
            protocolFeeInWeiAmount: constants.ZERO_AMOUNT,
 | 
			
		||||
            gas,
 | 
			
		||||
        },
 | 
			
		||||
        sourceBreakdown: {
 | 
			
		||||
            [ERC20BridgeSource.MultiHop]: {
 | 
			
		||||
                proportion: new BigNumber(1),
 | 
			
		||||
                intermediateToken: secondHopOrder.takerToken,
 | 
			
		||||
                hops: [firstHopFill.source, secondHopFill.source],
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getSwapQuoteOrdersBreakdown(fillAmountBySource: { [source: string]: BigNumber }): SwapQuoteOrdersBreakdown {
 | 
			
		||||
    const totalFillAmount = BigNumber.sum(...Object.values(fillAmountBySource));
 | 
			
		||||
    const breakdown: SwapQuoteOrdersBreakdown = {};
 | 
			
		||||
    Object.entries(fillAmountBySource).forEach(([s, fillAmount]) => {
 | 
			
		||||
        const source = s as keyof SwapQuoteOrdersBreakdown;
 | 
			
		||||
        if (source === ERC20BridgeSource.MultiHop) {
 | 
			
		||||
            // TODO jacob has a different breakdown
 | 
			
		||||
        } else {
 | 
			
		||||
            breakdown[source] = fillAmount.div(totalFillAmount);
 | 
			
		||||
    const getNextFillAmount = (fillResults: QuoteFillResult[]) => {
 | 
			
		||||
        if (fillResults.length === 0) {
 | 
			
		||||
            return fillAmount;
 | 
			
		||||
        }
 | 
			
		||||
        const lastFillResult = fillResults[fillResults.length - 1];
 | 
			
		||||
        const { totalTakerAssetAmount, makerAssetAmount } =  lastFillResult;
 | 
			
		||||
        return side === MarketOperation.Sell
 | 
			
		||||
            ? makerAssetAmount : totalTakerAssetAmount;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const bestCaseFillResults = [];
 | 
			
		||||
    const worstCaseFillResults = [];
 | 
			
		||||
    const tokenPath = [];
 | 
			
		||||
    for (const [i, hop] of hops.entries()) {
 | 
			
		||||
        if (i === 0 || i < hops.length - 1) {
 | 
			
		||||
            tokenPath.push(hop.takerToken);
 | 
			
		||||
        }
 | 
			
		||||
        if (i === tokenPath.length - 1) {
 | 
			
		||||
            tokenPath.push(hop.makerToken);
 | 
			
		||||
        }
 | 
			
		||||
        const bestCaseFillResult = simulateBestCaseFill({
 | 
			
		||||
            gasPrice,
 | 
			
		||||
            side,
 | 
			
		||||
            orders: hop.orders,
 | 
			
		||||
            fillAmount: getNextFillAmount(bestCaseFillResults),
 | 
			
		||||
            opts: {},
 | 
			
		||||
        });
 | 
			
		||||
        bestCaseFillResults.push(bestCaseFillResult);
 | 
			
		||||
 | 
			
		||||
        const worstCaseFillResult = simulateWorstCaseFill({
 | 
			
		||||
            gasPrice,
 | 
			
		||||
            side,
 | 
			
		||||
            orders: hop.orders,
 | 
			
		||||
            fillAmount: getNextFillAmount(worstCaseFillResults),
 | 
			
		||||
            opts: { slippage },
 | 
			
		||||
        });
 | 
			
		||||
        worstCaseFillResults.push(worstCaseFillResult);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const combinedBestCaseFillResult = combineQuoteFillResults(bestCaseFillResults);
 | 
			
		||||
    const combinedWorstCaseFillResult = combineQuoteFillResults(worstCaseFillResults);
 | 
			
		||||
    const sourceBreakdown = getSwapQuoteOrdersBreakdown(side, tokenPath, bestCaseFillResults);
 | 
			
		||||
    return {
 | 
			
		||||
        sourceBreakdown,
 | 
			
		||||
        bestCaseQuoteInfo: fillResultsToQuoteInfo(combinedBestCaseFillResult),
 | 
			
		||||
        worstCaseQuoteInfo: fillResultsToQuoteInfo(combinedWorstCaseFillResult),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function combineQuoteFillResults(fillResults: QuoteFillResult[]): QuoteFillResult {
 | 
			
		||||
    if (fillResults.length === 0) {
 | 
			
		||||
        throw new Error(`Empty fillResults array`);
 | 
			
		||||
    }
 | 
			
		||||
    const lastResult = fillResults[fillResults.length - 1];
 | 
			
		||||
    const r = {
 | 
			
		||||
        ...fillResults[0],
 | 
			
		||||
       makerAssetAmount: lastResult.makerAssetAmount,
 | 
			
		||||
       totalMakerAssetAmount: lastResult.totalMakerAssetAmount,
 | 
			
		||||
   };
 | 
			
		||||
    for (const fr of fillResults.slice(1)) {
 | 
			
		||||
        r.gas += fr.gas + 30e3;
 | 
			
		||||
        r.protocolFeeAmount = r.protocolFeeAmount.plus(fr.protocolFeeAmount);
 | 
			
		||||
    }
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getSwapQuoteOrdersBreakdown(side: MarketOperation, tokenPath: Address[], hopFillResults: QuoteFillResult[]): SwapQuoteOrdersBreakdown {
 | 
			
		||||
    const cumulativeFillRatioBySource: Partial<{ [key in ERC20BridgeSource]: number }> = {};
 | 
			
		||||
    for (const hop of hopFillResults) {
 | 
			
		||||
        const hopTotalFillAmount = side === MarketOperation.Sell
 | 
			
		||||
            ? hop.totalTakerAssetAmount
 | 
			
		||||
            : hop.totalMakerAssetAmount;
 | 
			
		||||
        for (const [source, sourceFillAmount] of Object.entries(hop.fillAmountBySource)) {
 | 
			
		||||
            cumulativeFillRatioBySource[source as ERC20BridgeSource] =
 | 
			
		||||
                (cumulativeFillRatioBySource[source as ERC20BridgeSource] || 0)
 | 
			
		||||
                + sourceFillAmount.div(hopTotalFillAmount).toNumber();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    const globalFillRatiosSum = Object.values(cumulativeFillRatioBySource).reduce((a, v) => a! + v!, 0);
 | 
			
		||||
    if (!globalFillRatiosSum) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    const breakdown: SwapQuoteOrdersBreakdown = {};
 | 
			
		||||
    for (const [source, fillRatio] of Object.entries(cumulativeFillRatioBySource)) {
 | 
			
		||||
        (breakdown as any)[source] = fillRatio! / globalFillRatiosSum;
 | 
			
		||||
    }
 | 
			
		||||
    const hopBreakdowns = hopFillResults.map(hop => {
 | 
			
		||||
        const hopTotalFillAmount = side === MarketOperation.Sell
 | 
			
		||||
            ? hop.totalTakerAssetAmount
 | 
			
		||||
            : hop.totalMakerAssetAmount;
 | 
			
		||||
        return Object.assign(
 | 
			
		||||
            {},
 | 
			
		||||
            ...Object.entries(hop.fillAmountBySource).map(([source, sourceFillAmount]) => ({
 | 
			
		||||
                [source as ERC20BridgeSource]: sourceFillAmount.div(hopTotalFillAmount).toNumber(),
 | 
			
		||||
            })),
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
    if (hopFillResults.length > 1) {
 | 
			
		||||
        return {
 | 
			
		||||
            [ERC20BridgeSource.MultiHop]: {
 | 
			
		||||
                proportion: 1,
 | 
			
		||||
                tokenPath: tokenPath,
 | 
			
		||||
                breakdowns: hopBreakdowns,
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
    return breakdown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,9 @@
 | 
			
		||||
import { ChainId } from '@0x/contract-addresses';
 | 
			
		||||
import { BlockParam, ContractAddresses, GethCallOverrides } from '@0x/contract-wrappers';
 | 
			
		||||
import {
 | 
			
		||||
    FillQuoteTransformerLimitOrderInfo,
 | 
			
		||||
    FillQuoteTransformerOrderType,
 | 
			
		||||
    FillQuoteTransformerRfqOrderInfo,
 | 
			
		||||
    LimitOrderFields,
 | 
			
		||||
    RfqOrder,
 | 
			
		||||
    RfqOrderFields,
 | 
			
		||||
@@ -16,12 +18,21 @@ import {
 | 
			
		||||
    ERC20BridgeSource,
 | 
			
		||||
    GetMarketOrdersOpts,
 | 
			
		||||
    LiquidityProviderRegistry,
 | 
			
		||||
    OptimizedMarketOrder,
 | 
			
		||||
    LiquidityProviderFillData,
 | 
			
		||||
    TokenAdjacencyGraph,
 | 
			
		||||
    BridgeFillData,
 | 
			
		||||
    CurveFillData,
 | 
			
		||||
    UniswapV2FillData,
 | 
			
		||||
    UniswapV3FillData,
 | 
			
		||||
    NativeOrderFillData,
 | 
			
		||||
    MooniswapFillData,
 | 
			
		||||
} from './utils/market_operation_utils/types';
 | 
			
		||||
import { PriceComparisonsReport, QuoteReport } from './utils/quote_report_generator';
 | 
			
		||||
import { MetricsProxy } from './utils/quote_requestor';
 | 
			
		||||
 | 
			
		||||
export type Address = string;
 | 
			
		||||
export type Bytes = string;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * expiryBufferMs: The number of seconds to add when calculating whether an order is expired or not. Defaults to 300s (5m).
 | 
			
		||||
 * permittedOrderFeeTypes: A set of all the takerFee types that OrderPruner will filter for
 | 
			
		||||
@@ -37,19 +48,9 @@ export interface SignedOrder<T> {
 | 
			
		||||
    signature: Signature;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type SignedNativeOrder = SignedOrder<LimitOrderFields> | SignedOrder<RfqOrderFields>;
 | 
			
		||||
export type NativeOrderWithFillableAmounts = SignedNativeOrder & NativeOrderFillableAmountFields;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * fillableMakerAmount: Amount of makerAsset that is fillable
 | 
			
		||||
 * fillableTakerAmount: Amount of takerAsset that is fillable
 | 
			
		||||
 * fillableTakerFeeAmount: Amount of takerFee paid to fill fillableTakerAmount
 | 
			
		||||
 */
 | 
			
		||||
export interface NativeOrderFillableAmountFields {
 | 
			
		||||
    fillableMakerAmount: BigNumber;
 | 
			
		||||
    fillableTakerAmount: BigNumber;
 | 
			
		||||
    fillableTakerFeeAmount: BigNumber;
 | 
			
		||||
}
 | 
			
		||||
export type SignedRfqOrder = SignedOrder<RfqOrderFields>;
 | 
			
		||||
export type SignedLimitOrder = SignedOrder<LimitOrderFields>;
 | 
			
		||||
export type SignedNativeOrder = SignedLimitOrder | SignedRfqOrder;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents the metadata to call a smart contract with calldata.
 | 
			
		||||
@@ -166,19 +167,72 @@ export interface SwapQuoteBase {
 | 
			
		||||
    takerToken: string;
 | 
			
		||||
    makerToken: string;
 | 
			
		||||
    gasPrice: BigNumber;
 | 
			
		||||
    orders: OptimizedMarketOrder[];
 | 
			
		||||
    hops: SwapQuoteHop[];
 | 
			
		||||
    bestCaseQuoteInfo: SwapQuoteInfo;
 | 
			
		||||
    worstCaseQuoteInfo: SwapQuoteInfo;
 | 
			
		||||
    sourceBreakdown: SwapQuoteOrdersBreakdown;
 | 
			
		||||
    quoteReport?: QuoteReport;
 | 
			
		||||
    priceComparisonsReport?: PriceComparisonsReport;
 | 
			
		||||
    isTwoHop: boolean;
 | 
			
		||||
    makerTokenDecimals: number;
 | 
			
		||||
    takerTokenDecimals: number;
 | 
			
		||||
    takerAmountPerEth: BigNumber;
 | 
			
		||||
    makerAmountPerEth: BigNumber;
 | 
			
		||||
    maxSlippage: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteHop {
 | 
			
		||||
    takerToken: Address;
 | 
			
		||||
    makerToken: Address;
 | 
			
		||||
    makerAmount: BigNumber;
 | 
			
		||||
    takerAmount: BigNumber;
 | 
			
		||||
    minMakerAmount: BigNumber;
 | 
			
		||||
    maxTakerAmount: BigNumber;
 | 
			
		||||
    sourceFlags: bigint;
 | 
			
		||||
    orders: SwapQuoteOrder[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteOrder {
 | 
			
		||||
    type: FillQuoteTransformerOrderType; // should correspond with TFillData
 | 
			
		||||
    source: ERC20BridgeSource;
 | 
			
		||||
    makerToken: string;
 | 
			
		||||
    takerToken: string;
 | 
			
		||||
    gasCost: number;
 | 
			
		||||
    makerAmount: BigNumber;
 | 
			
		||||
    takerAmount: BigNumber;
 | 
			
		||||
    isFallback: boolean;
 | 
			
		||||
    fillData?: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteBridgeOrder<TFillData extends BridgeFillData> extends SwapQuoteOrder {
 | 
			
		||||
    fillData: TFillData;
 | 
			
		||||
    minMakerAmount: BigNumber;
 | 
			
		||||
    maxTakerAmount: BigNumber;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteGenericBridgeOrder extends SwapQuoteBridgeOrder<BridgeFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteUniswapV2BridgeOrder extends SwapQuoteBridgeOrder<UniswapV2FillData> {}
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteUniswapV3BridgeOrder extends SwapQuoteBridgeOrder<UniswapV3FillData> {}
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteLiquidityProviderBridgeOrder extends SwapQuoteBridgeOrder<LiquidityProviderFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteMooniswapBridgeOrder extends SwapQuoteBridgeOrder<MooniswapFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteCurveBridgeOrder extends SwapQuoteBridgeOrder<CurveFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteLimitOrder extends SwapQuoteOrder {
 | 
			
		||||
    type: FillQuoteTransformerOrderType.Limit;
 | 
			
		||||
    fillData: NativeOrderFillData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteRfqOrder extends SwapQuoteOrder {
 | 
			
		||||
    type: FillQuoteTransformerOrderType.Rfq;
 | 
			
		||||
    fillData: NativeOrderFillData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type SwapQuoteNativeOrder = SwapQuoteLimitOrder | SwapQuoteRfqOrder;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * takerAssetFillAmount: The amount of takerAsset sold for makerAsset.
 | 
			
		||||
 * type: Specified MarketOperation the SwapQuote is provided for
 | 
			
		||||
@@ -220,15 +274,17 @@ export interface SwapQuoteInfo {
 | 
			
		||||
 * percentage breakdown of each liquidity source used in quote
 | 
			
		||||
 */
 | 
			
		||||
export type SwapQuoteOrdersBreakdown = Partial<
 | 
			
		||||
    { [key in Exclude<ERC20BridgeSource, typeof ERC20BridgeSource.MultiHop>]: BigNumber } & {
 | 
			
		||||
        [ERC20BridgeSource.MultiHop]: {
 | 
			
		||||
            proportion: BigNumber;
 | 
			
		||||
            intermediateToken: string;
 | 
			
		||||
            hops: ERC20BridgeSource[];
 | 
			
		||||
        };
 | 
			
		||||
    { [key in Exclude<ERC20BridgeSource, typeof ERC20BridgeSource.MultiHop>]: number } & {
 | 
			
		||||
        [ERC20BridgeSource.MultiHop]: SwapQuoteMultiHopBreakdown;
 | 
			
		||||
    }
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
export interface SwapQuoteMultiHopBreakdown {
 | 
			
		||||
    proportion: number;
 | 
			
		||||
    tokenPath: Address[];
 | 
			
		||||
    breakdowns: Partial<{ [key in ERC20BridgeSource]: number }>[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * nativeExclusivelyRFQ: if set to `true`, Swap quote will exclude Open Orderbook liquidity.
 | 
			
		||||
 *                       If set to `true` and `ERC20BridgeSource.Native` is part of the `excludedSources`
 | 
			
		||||
@@ -326,15 +382,16 @@ export interface SwapQuoterOpts extends OrderPrunerOpts {
 | 
			
		||||
    chainId: ChainId;
 | 
			
		||||
    orderRefreshIntervalMs: number;
 | 
			
		||||
    expiryBufferMs: number;
 | 
			
		||||
    ethereumRpcUrl?: string;
 | 
			
		||||
    // ethereumRpcUrl?: string;
 | 
			
		||||
    contractAddresses?: AssetSwapperContractAddresses;
 | 
			
		||||
    samplerGasLimit?: number;
 | 
			
		||||
    multiBridgeAddress?: string;
 | 
			
		||||
    // multiBridgeAddress?: string;
 | 
			
		||||
    ethGasStationUrl?: string;
 | 
			
		||||
    rfqt?: SwapQuoterRfqOpts;
 | 
			
		||||
    samplerOverrides?: SamplerOverrides;
 | 
			
		||||
    tokenAdjacencyGraph?: TokenAdjacencyGraph;
 | 
			
		||||
    liquidityProviderRegistry?: LiquidityProviderRegistry;
 | 
			
		||||
    // samplerOverrides?: SamplerOverrides;
 | 
			
		||||
    // tokenAdjacencyGraph?: TokenAdjacencyGraph;
 | 
			
		||||
    // liquidityProviderRegistry?: LiquidityProviderRegistry;
 | 
			
		||||
    samplerServiceUrl: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -410,8 +467,6 @@ export interface SamplerCallResult {
 | 
			
		||||
    data: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
 | 
			
		||||
 | 
			
		||||
export enum AltQuoteModel {
 | 
			
		||||
    Firm = 'firm',
 | 
			
		||||
    Indicative = 'indicative',
 | 
			
		||||
 
 | 
			
		||||
@@ -1,34 +0,0 @@
 | 
			
		||||
import { SupportedProvider } from '@0x/dev-utils';
 | 
			
		||||
import { SDK } from '@bancor/sdk';
 | 
			
		||||
import { Ethereum } from '@bancor/sdk/dist/blockchains/ethereum';
 | 
			
		||||
import { BlockchainType } from '@bancor/sdk/dist/types';
 | 
			
		||||
 | 
			
		||||
import { MAINNET_TOKENS } from './constants';
 | 
			
		||||
 | 
			
		||||
const findToken = (tokenAddress: string, graph: object): string =>
 | 
			
		||||
    // If we're looking for WETH it is stored by Bancor as the 0xeee address
 | 
			
		||||
    tokenAddress.toLowerCase() === MAINNET_TOKENS.WETH.toLowerCase()
 | 
			
		||||
        ? '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'
 | 
			
		||||
        : Object.keys(graph).filter(k => k.toLowerCase() === tokenAddress.toLowerCase())[0];
 | 
			
		||||
 | 
			
		||||
export class BancorService {
 | 
			
		||||
    public static async createAsync(provider: SupportedProvider): Promise<BancorService> {
 | 
			
		||||
        const sdk = await SDK.create({ ethereumNodeEndpoint: provider });
 | 
			
		||||
        const service = new BancorService(sdk);
 | 
			
		||||
        return service;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constructor(public sdk: SDK) {}
 | 
			
		||||
    public getPaths(_fromToken: string, _toToken: string): string[][] {
 | 
			
		||||
        // HACK: We reach into the blockchain object and pull in it's cache of tokens
 | 
			
		||||
        // and we use it's internal non-async getPathsFunc
 | 
			
		||||
        try {
 | 
			
		||||
            const blockchain = this.sdk._core.blockchains[BlockchainType.Ethereum] as Ethereum;
 | 
			
		||||
            const fromToken = findToken(_fromToken, blockchain.graph);
 | 
			
		||||
            const toToken = findToken(_toToken, blockchain.graph);
 | 
			
		||||
            return blockchain.getPathsFunc.bind(blockchain)(fromToken, toToken);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,528 +0,0 @@
 | 
			
		||||
import { ChainId } from '@0x/contract-addresses';
 | 
			
		||||
import { BigNumber, NULL_BYTES } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
    ACRYPTOS_BSC_INFOS,
 | 
			
		||||
    APESWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    BAKERYSWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    BELT_BSC_INFOS,
 | 
			
		||||
    CAFESWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    CHEESESWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    COMETHSWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    COMPONENT_POOLS_BY_CHAIN_ID,
 | 
			
		||||
    CRYPTO_COM_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    CURVE_FANTOM_INFOS,
 | 
			
		||||
    CURVE_MAINNET_INFOS,
 | 
			
		||||
    CURVE_POLYGON_INFOS,
 | 
			
		||||
    CURVE_V2_FANTOM_INFOS,
 | 
			
		||||
    CURVE_V2_MAINNET_INFOS,
 | 
			
		||||
    CURVE_V2_POLYGON_INFOS,
 | 
			
		||||
    DFYN_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    ELLIPSIS_BSC_INFOS,
 | 
			
		||||
    FIREBIRDONESWAP_BSC_INFOS,
 | 
			
		||||
    FIREBIRDONESWAP_POLYGON_INFOS,
 | 
			
		||||
    IRONSWAP_POLYGON_INFOS,
 | 
			
		||||
    JETSWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    JULSWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    KYBER_BANNED_RESERVES,
 | 
			
		||||
    KYBER_BRIDGED_LIQUIDITY_PREFIX,
 | 
			
		||||
    MAX_DODOV2_POOLS_QUERIED,
 | 
			
		||||
    MAX_KYBER_RESERVES_QUERIED,
 | 
			
		||||
    MSTABLE_POOLS_BY_CHAIN_ID,
 | 
			
		||||
    NERVE_BSC_INFOS,
 | 
			
		||||
    NULL_ADDRESS,
 | 
			
		||||
    PANCAKESWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    PANCAKESWAPV2_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    PANGOLIN_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    POLYDEX_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    QUICKSWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    SADDLE_MAINNET_INFOS,
 | 
			
		||||
    SHELL_POOLS_BY_CHAIN_ID,
 | 
			
		||||
    SHIBASWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    SMOOTHY_BSC_INFOS,
 | 
			
		||||
    SMOOTHY_MAINNET_INFOS,
 | 
			
		||||
    SNOWSWAP_MAINNET_INFOS,
 | 
			
		||||
    SPIRITSWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    SPOOKYSWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    SUSHISWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    SWERVE_MAINNET_INFOS,
 | 
			
		||||
    TRADER_JOE_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    UNISWAPV2_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    WAULTSWAP_ROUTER_BY_CHAIN_ID,
 | 
			
		||||
    XSIGMA_MAINNET_INFOS,
 | 
			
		||||
} from './constants';
 | 
			
		||||
import { CurveInfo, ERC20BridgeSource } from './types';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Filter Kyber reserves which should not be used (0xbb bridged reserves)
 | 
			
		||||
 * @param reserveId Kyber reserveId
 | 
			
		||||
 */
 | 
			
		||||
export function isAllowedKyberReserveId(reserveId: string): boolean {
 | 
			
		||||
    return (
 | 
			
		||||
        reserveId !== NULL_BYTES &&
 | 
			
		||||
        !reserveId.startsWith(KYBER_BRIDGED_LIQUIDITY_PREFIX) &&
 | 
			
		||||
        !KYBER_BANNED_RESERVES.includes(reserveId)
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tslint:disable-next-line: completed-docs ban-types
 | 
			
		||||
export function isValidAddress(address: string | String): address is string {
 | 
			
		||||
    return (typeof address === 'string' || address instanceof String) && address.toString() !== NULL_ADDRESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the offsets to be used to discover Kyber reserves
 | 
			
		||||
 */
 | 
			
		||||
export function getKyberOffsets(): BigNumber[] {
 | 
			
		||||
    return Array(MAX_KYBER_RESERVES_QUERIED)
 | 
			
		||||
        .fill(0)
 | 
			
		||||
        .map((_v, i) => new BigNumber(i));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tslint:disable completed-docs
 | 
			
		||||
export function getDodoV2Offsets(): BigNumber[] {
 | 
			
		||||
    return Array(MAX_DODOV2_POOLS_QUERIED)
 | 
			
		||||
        .fill(0)
 | 
			
		||||
        .map((_v, i) => new BigNumber(i));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tslint:disable completed-docs
 | 
			
		||||
export function getShellsForPair(chainId: ChainId, takerToken: string, makerToken: string): string[] {
 | 
			
		||||
    if (chainId !== ChainId.Mainnet) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(SHELL_POOLS_BY_CHAIN_ID[chainId])
 | 
			
		||||
        .filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t)))
 | 
			
		||||
        .map(i => i.poolAddress);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tslint:disable completed-docs
 | 
			
		||||
export function getComponentForPair(chainId: ChainId, takerToken: string, makerToken: string): string[] {
 | 
			
		||||
    if (chainId !== ChainId.Mainnet) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(COMPONENT_POOLS_BY_CHAIN_ID[chainId])
 | 
			
		||||
        .filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t)))
 | 
			
		||||
        .map(i => i.poolAddress);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tslint:disable completed-docs
 | 
			
		||||
export function getMStableForPair(chainId: ChainId, takerToken: string, makerToken: string): string[] {
 | 
			
		||||
    if (chainId !== ChainId.Mainnet && chainId !== ChainId.Polygon) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(MSTABLE_POOLS_BY_CHAIN_ID[chainId])
 | 
			
		||||
        .filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t)))
 | 
			
		||||
        .map(i => i.poolAddress);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tslint:disable completed-docs
 | 
			
		||||
export function getCurveInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    switch (chainId) {
 | 
			
		||||
        case ChainId.Mainnet:
 | 
			
		||||
            return Object.values(CURVE_MAINNET_INFOS).filter(c =>
 | 
			
		||||
                [makerToken, takerToken].every(
 | 
			
		||||
                    t =>
 | 
			
		||||
                        (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                        (c.tokens.includes(t) &&
 | 
			
		||||
                            [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Polygon:
 | 
			
		||||
            return Object.values(CURVE_POLYGON_INFOS).filter(c =>
 | 
			
		||||
                [makerToken, takerToken].every(
 | 
			
		||||
                    t =>
 | 
			
		||||
                        (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                        (c.tokens.includes(t) &&
 | 
			
		||||
                            [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Fantom:
 | 
			
		||||
            return Object.values(CURVE_FANTOM_INFOS).filter(c =>
 | 
			
		||||
                [makerToken, takerToken].every(
 | 
			
		||||
                    t =>
 | 
			
		||||
                        (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                        (c.tokens.includes(t) &&
 | 
			
		||||
                            [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        default:
 | 
			
		||||
            return [];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tslint:disable completed-docs
 | 
			
		||||
export function getCurveV2InfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    switch (chainId) {
 | 
			
		||||
        case ChainId.Mainnet:
 | 
			
		||||
            return Object.values(CURVE_V2_MAINNET_INFOS).filter(c =>
 | 
			
		||||
                [makerToken, takerToken].every(
 | 
			
		||||
                    t =>
 | 
			
		||||
                        (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                        (c.tokens.includes(t) &&
 | 
			
		||||
                            [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Polygon:
 | 
			
		||||
            return Object.values(CURVE_V2_POLYGON_INFOS).filter(c =>
 | 
			
		||||
                [makerToken, takerToken].every(
 | 
			
		||||
                    t =>
 | 
			
		||||
                        (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                        (c.tokens.includes(t) &&
 | 
			
		||||
                            [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        case ChainId.Fantom:
 | 
			
		||||
            return Object.values(CURVE_V2_FANTOM_INFOS).filter(c =>
 | 
			
		||||
                [makerToken, takerToken].every(
 | 
			
		||||
                    t =>
 | 
			
		||||
                        (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                        (c.tokens.includes(t) &&
 | 
			
		||||
                            [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        default:
 | 
			
		||||
            return [];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getSwerveInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId !== ChainId.Mainnet) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(SWERVE_MAINNET_INFOS).filter(c =>
 | 
			
		||||
        [makerToken, takerToken].every(
 | 
			
		||||
            t =>
 | 
			
		||||
                (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
        ),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getSnowSwapInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId !== ChainId.Mainnet) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(SNOWSWAP_MAINNET_INFOS).filter(c =>
 | 
			
		||||
        [makerToken, takerToken].every(
 | 
			
		||||
            t =>
 | 
			
		||||
                (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
        ),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getNerveInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId !== ChainId.BSC) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(NERVE_BSC_INFOS).filter(c =>
 | 
			
		||||
        [makerToken, takerToken].every(
 | 
			
		||||
            t =>
 | 
			
		||||
                (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
        ),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getFirebirdOneSwapInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId === ChainId.BSC) {
 | 
			
		||||
        return Object.values(FIREBIRDONESWAP_BSC_INFOS).filter(c =>
 | 
			
		||||
            [makerToken, takerToken].every(
 | 
			
		||||
                t =>
 | 
			
		||||
                    (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                    (c.tokens.includes(t) &&
 | 
			
		||||
                        [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
    } else if (chainId === ChainId.Polygon) {
 | 
			
		||||
        return Object.values(FIREBIRDONESWAP_POLYGON_INFOS).filter(c =>
 | 
			
		||||
            [makerToken, takerToken].every(
 | 
			
		||||
                t =>
 | 
			
		||||
                    (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                    (c.tokens.includes(t) &&
 | 
			
		||||
                        [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
    } else {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getBeltInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId !== ChainId.BSC) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(BELT_BSC_INFOS).filter(c =>
 | 
			
		||||
        [makerToken, takerToken].every(
 | 
			
		||||
            t =>
 | 
			
		||||
                (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
        ),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getEllipsisInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId !== ChainId.BSC) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(ELLIPSIS_BSC_INFOS).filter(c =>
 | 
			
		||||
        [makerToken, takerToken].every(
 | 
			
		||||
            t =>
 | 
			
		||||
                (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
        ),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getSmoothyInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId === ChainId.BSC) {
 | 
			
		||||
        return Object.values(SMOOTHY_BSC_INFOS).filter(c =>
 | 
			
		||||
            [makerToken, takerToken].every(
 | 
			
		||||
                t =>
 | 
			
		||||
                    (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                    (c.tokens.includes(t) &&
 | 
			
		||||
                        [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
    } else if (chainId === ChainId.Mainnet) {
 | 
			
		||||
        return Object.values(SMOOTHY_MAINNET_INFOS).filter(c =>
 | 
			
		||||
            [makerToken, takerToken].every(
 | 
			
		||||
                t =>
 | 
			
		||||
                    (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                    (c.tokens.includes(t) &&
 | 
			
		||||
                        [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
    } else {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getSaddleInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId !== ChainId.Mainnet) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(SADDLE_MAINNET_INFOS).filter(c =>
 | 
			
		||||
        [makerToken, takerToken].every(
 | 
			
		||||
            t =>
 | 
			
		||||
                (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
        ),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getIronSwapInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId !== ChainId.Polygon) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(IRONSWAP_POLYGON_INFOS).filter(c =>
 | 
			
		||||
        [makerToken, takerToken].every(
 | 
			
		||||
            t =>
 | 
			
		||||
                (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
        ),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getXSigmaInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId !== ChainId.Mainnet) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(XSIGMA_MAINNET_INFOS).filter(c =>
 | 
			
		||||
        [makerToken, takerToken].every(
 | 
			
		||||
            t =>
 | 
			
		||||
                (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
        ),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getAcryptosInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] {
 | 
			
		||||
    if (chainId !== ChainId.BSC) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    return Object.values(ACRYPTOS_BSC_INFOS).filter(c =>
 | 
			
		||||
        [makerToken, takerToken].every(
 | 
			
		||||
            t =>
 | 
			
		||||
                (c.tokens.includes(t) && c.metaTokens === undefined) ||
 | 
			
		||||
                (c.tokens.includes(t) && [makerToken, takerToken].filter(v => c.metaTokens?.includes(v)).length > 0),
 | 
			
		||||
        ),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getShellLikeInfosForPair(
 | 
			
		||||
    chainId: ChainId,
 | 
			
		||||
    takerToken: string,
 | 
			
		||||
    makerToken: string,
 | 
			
		||||
    source: ERC20BridgeSource.Shell | ERC20BridgeSource.Component | ERC20BridgeSource.MStable,
 | 
			
		||||
): string[] {
 | 
			
		||||
    switch (source) {
 | 
			
		||||
        case ERC20BridgeSource.Shell:
 | 
			
		||||
            return getShellsForPair(chainId, takerToken, makerToken);
 | 
			
		||||
        case ERC20BridgeSource.Component:
 | 
			
		||||
            return getComponentForPair(chainId, takerToken, makerToken);
 | 
			
		||||
        case ERC20BridgeSource.MStable:
 | 
			
		||||
            return getMStableForPair(chainId, takerToken, makerToken);
 | 
			
		||||
        default:
 | 
			
		||||
            throw new Error(`Unknown Shell like source ${source}`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface CurveDetailedInfo extends CurveInfo {
 | 
			
		||||
    makerTokenIdx: number;
 | 
			
		||||
    takerTokenIdx: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getCurveLikeInfosForPair(
 | 
			
		||||
    chainId: ChainId,
 | 
			
		||||
    takerToken: string,
 | 
			
		||||
    makerToken: string,
 | 
			
		||||
    source:
 | 
			
		||||
        | ERC20BridgeSource.Curve
 | 
			
		||||
        | ERC20BridgeSource.CurveV2
 | 
			
		||||
        | ERC20BridgeSource.Swerve
 | 
			
		||||
        | ERC20BridgeSource.SnowSwap
 | 
			
		||||
        | ERC20BridgeSource.Nerve
 | 
			
		||||
        | ERC20BridgeSource.Belt
 | 
			
		||||
        | ERC20BridgeSource.Ellipsis
 | 
			
		||||
        | ERC20BridgeSource.Smoothy
 | 
			
		||||
        | ERC20BridgeSource.Saddle
 | 
			
		||||
        | ERC20BridgeSource.IronSwap
 | 
			
		||||
        | ERC20BridgeSource.XSigma
 | 
			
		||||
        | ERC20BridgeSource.FirebirdOneSwap
 | 
			
		||||
        | ERC20BridgeSource.ACryptos,
 | 
			
		||||
): CurveDetailedInfo[] {
 | 
			
		||||
    let pools: CurveInfo[] = [];
 | 
			
		||||
    switch (source) {
 | 
			
		||||
        case ERC20BridgeSource.Curve:
 | 
			
		||||
            pools = getCurveInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.CurveV2:
 | 
			
		||||
            pools = getCurveV2InfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Swerve:
 | 
			
		||||
            pools = getSwerveInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.SnowSwap:
 | 
			
		||||
            pools = getSnowSwapInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Nerve:
 | 
			
		||||
            pools = getNerveInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Belt:
 | 
			
		||||
            pools = getBeltInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Ellipsis:
 | 
			
		||||
            pools = getEllipsisInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Smoothy:
 | 
			
		||||
            pools = getSmoothyInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Saddle:
 | 
			
		||||
            pools = getSaddleInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.XSigma:
 | 
			
		||||
            pools = getXSigmaInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.FirebirdOneSwap:
 | 
			
		||||
            pools = getFirebirdOneSwapInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.IronSwap:
 | 
			
		||||
            pools = getIronSwapInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.ACryptos:
 | 
			
		||||
            pools = getAcryptosInfosForPair(chainId, takerToken, makerToken);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            throw new Error(`Unknown Curve like source ${source}`);
 | 
			
		||||
    }
 | 
			
		||||
    return pools.map(pool => ({
 | 
			
		||||
        ...pool,
 | 
			
		||||
        makerTokenIdx: pool.tokens.indexOf(makerToken),
 | 
			
		||||
        takerTokenIdx: pool.tokens.indexOf(takerToken),
 | 
			
		||||
    }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function uniswapV2LikeRouterAddress(
 | 
			
		||||
    chainId: ChainId,
 | 
			
		||||
    source:
 | 
			
		||||
        | ERC20BridgeSource.UniswapV2
 | 
			
		||||
        | ERC20BridgeSource.SushiSwap
 | 
			
		||||
        | ERC20BridgeSource.CryptoCom
 | 
			
		||||
        | ERC20BridgeSource.PancakeSwap
 | 
			
		||||
        | ERC20BridgeSource.PancakeSwapV2
 | 
			
		||||
        | ERC20BridgeSource.BakerySwap
 | 
			
		||||
        | ERC20BridgeSource.ApeSwap
 | 
			
		||||
        | ERC20BridgeSource.CafeSwap
 | 
			
		||||
        | ERC20BridgeSource.CheeseSwap
 | 
			
		||||
        | ERC20BridgeSource.JulSwap
 | 
			
		||||
        | ERC20BridgeSource.QuickSwap
 | 
			
		||||
        | ERC20BridgeSource.ComethSwap
 | 
			
		||||
        | ERC20BridgeSource.Dfyn
 | 
			
		||||
        | ERC20BridgeSource.WaultSwap
 | 
			
		||||
        | ERC20BridgeSource.Polydex
 | 
			
		||||
        | ERC20BridgeSource.ShibaSwap
 | 
			
		||||
        | ERC20BridgeSource.JetSwap
 | 
			
		||||
        | ERC20BridgeSource.TraderJoe
 | 
			
		||||
        | ERC20BridgeSource.Pangolin
 | 
			
		||||
        | ERC20BridgeSource.SpookySwap
 | 
			
		||||
        | ERC20BridgeSource.SpiritSwap,
 | 
			
		||||
): string {
 | 
			
		||||
    switch (source) {
 | 
			
		||||
        case ERC20BridgeSource.UniswapV2:
 | 
			
		||||
            return UNISWAPV2_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.SushiSwap:
 | 
			
		||||
            return SUSHISWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.CryptoCom:
 | 
			
		||||
            return CRYPTO_COM_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.PancakeSwap:
 | 
			
		||||
            return PANCAKESWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.PancakeSwapV2:
 | 
			
		||||
            return PANCAKESWAPV2_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.BakerySwap:
 | 
			
		||||
            return BAKERYSWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.ApeSwap:
 | 
			
		||||
            return APESWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.CafeSwap:
 | 
			
		||||
            return CAFESWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.CheeseSwap:
 | 
			
		||||
            return CHEESESWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.JulSwap:
 | 
			
		||||
            return JULSWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.QuickSwap:
 | 
			
		||||
            return QUICKSWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.ComethSwap:
 | 
			
		||||
            return COMETHSWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.Dfyn:
 | 
			
		||||
            return DFYN_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.WaultSwap:
 | 
			
		||||
            return WAULTSWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.Polydex:
 | 
			
		||||
            return POLYDEX_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.ShibaSwap:
 | 
			
		||||
            return SHIBASWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.JetSwap:
 | 
			
		||||
            return JETSWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.Pangolin:
 | 
			
		||||
            return PANGOLIN_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.TraderJoe:
 | 
			
		||||
            return TRADER_JOE_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.SpookySwap:
 | 
			
		||||
            return SPOOKYSWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        case ERC20BridgeSource.SpiritSwap:
 | 
			
		||||
            return SPIRITSWAP_ROUTER_BY_CHAIN_ID[chainId];
 | 
			
		||||
        default:
 | 
			
		||||
            throw new Error(`Unknown UniswapV2 like source ${source}`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const BAD_TOKENS_BY_SOURCE: Partial<{ [key in ERC20BridgeSource]: string[] }> = {
 | 
			
		||||
    [ERC20BridgeSource.Uniswap]: [
 | 
			
		||||
        '0xb8c77482e45f1f44de1745f52c74426c631bdd52', // BNB
 | 
			
		||||
    ],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function isBadTokenForSource(token: string, source: ERC20BridgeSource): boolean {
 | 
			
		||||
    return (BAD_TOKENS_BY_SOURCE[source] || []).includes(token.toLowerCase());
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
import { Web3Wrapper } from '@0x/dev-utils';
 | 
			
		||||
import { FillQuoteTransformerOrderType } from '@0x/protocol-utils';
 | 
			
		||||
import { BigNumber, logUtils } from '@0x/utils';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
@@ -8,10 +7,6 @@ import { MarketOperation } from '../../types';
 | 
			
		||||
import { COMPARISON_PRICE_DECIMALS, SOURCE_FLAGS } from './constants';
 | 
			
		||||
import {
 | 
			
		||||
    ComparisonPrice,
 | 
			
		||||
    ERC20BridgeSource,
 | 
			
		||||
    ExchangeProxyOverhead,
 | 
			
		||||
    FeeEstimate,
 | 
			
		||||
    FeeSchedule,
 | 
			
		||||
    MarketSideLiquidity,
 | 
			
		||||
} from './types';
 | 
			
		||||
 | 
			
		||||
@@ -29,41 +24,20 @@ export function getComparisonPrices(
 | 
			
		||||
    adjustedRate: BigNumber,
 | 
			
		||||
    amount: BigNumber,
 | 
			
		||||
    marketSideLiquidity: MarketSideLiquidity,
 | 
			
		||||
    feeSchedule: FeeSchedule,
 | 
			
		||||
    exchangeProxyOverhead: ExchangeProxyOverhead,
 | 
			
		||||
    gasPrice: BigNumber,
 | 
			
		||||
): ComparisonPrice {
 | 
			
		||||
    let wholeOrder: BigNumber | undefined;
 | 
			
		||||
    let feeInEth: BigNumber | number;
 | 
			
		||||
 | 
			
		||||
    // HACK: get the fee penalty of a single 0x native order
 | 
			
		||||
    // The FeeSchedule function takes in a `FillData` object and returns a fee estimate in ETH
 | 
			
		||||
    // We don't have fill data here, we just want the cost of a single native order, so we pass in undefined
 | 
			
		||||
    // This works because the feeSchedule returns a constant for Native orders, this will need
 | 
			
		||||
    // to be tweaked if the feeSchedule for native orders uses the fillData passed in
 | 
			
		||||
    // 2 potential issues: there is no native fee schedule or the fee schedule depends on fill data
 | 
			
		||||
    if (feeSchedule[ERC20BridgeSource.Native] === undefined) {
 | 
			
		||||
        logUtils.warn('ComparisonPrice function did not find native order fee schedule');
 | 
			
		||||
 | 
			
		||||
        return { wholeOrder };
 | 
			
		||||
    } else {
 | 
			
		||||
        try {
 | 
			
		||||
            const fillFeeInEth = new BigNumber(
 | 
			
		||||
                (feeSchedule[ERC20BridgeSource.Native] as FeeEstimate)({ type: FillQuoteTransformerOrderType.Rfq }),
 | 
			
		||||
            );
 | 
			
		||||
            const exchangeProxyOverheadInEth = new BigNumber(exchangeProxyOverhead(SOURCE_FLAGS.RfqOrder));
 | 
			
		||||
            feeInEth = fillFeeInEth.plus(exchangeProxyOverheadInEth);
 | 
			
		||||
        } catch {
 | 
			
		||||
            logUtils.warn('Native order fee schedule requires fill data');
 | 
			
		||||
 | 
			
		||||
            return { wholeOrder };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    let feeInEth = gasPrice.times(100e3);
 | 
			
		||||
 | 
			
		||||
    const [inputAmountPerEth, outputAmountPerEth] = [
 | 
			
		||||
        marketSideLiquidity.tokenAmountPerEth[marketSideLiquidity.inputToken],
 | 
			
		||||
        marketSideLiquidity.tokenAmountPerEth[marketSideLiquidity.outputToken],
 | 
			
		||||
    ];
 | 
			
		||||
    // Calc native order fee penalty in output unit (maker units for sells, taker unit for buys)
 | 
			
		||||
    const feePenalty = !marketSideLiquidity.outputAmountPerEth.isZero()
 | 
			
		||||
        ? marketSideLiquidity.outputAmountPerEth.times(feeInEth)
 | 
			
		||||
    const feePenalty = !outputAmountPerEth.isZero()
 | 
			
		||||
        ? outputAmountPerEth.times(feeInEth)
 | 
			
		||||
        : // if it's a sell, the input token is the taker token
 | 
			
		||||
          marketSideLiquidity.inputAmountPerEth
 | 
			
		||||
          inputAmountPerEth
 | 
			
		||||
              .times(feeInEth)
 | 
			
		||||
              .times(marketSideLiquidity.side === MarketOperation.Sell ? adjustedRate : adjustedRate.pow(-1));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,10 +1,11 @@
 | 
			
		||||
import { FillQuoteTransformerOrderType } from '@0x/protocol-utils';
 | 
			
		||||
import { BigNumber, hexUtils } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { MarketOperation, NativeOrderWithFillableAmounts } from '../../types';
 | 
			
		||||
import { NativeOrderWithFillableAmounts } from '../native_orders';
 | 
			
		||||
import { MarketOperation } from '../../types';
 | 
			
		||||
 | 
			
		||||
import { POSITIVE_INF, SOURCE_FLAGS, ZERO_AMOUNT } from './constants';
 | 
			
		||||
import { DexSample, ERC20BridgeSource, FeeSchedule, Fill } from './types';
 | 
			
		||||
import { DexSample, ERC20BridgeSource, Fill, GenericBridgeFill, NativeOrderFill } from './types';
 | 
			
		||||
 | 
			
		||||
// tslint:disable: prefer-for-of no-bitwise completed-docs
 | 
			
		||||
 | 
			
		||||
@@ -18,12 +19,9 @@ export function createFills(opts: {
 | 
			
		||||
    targetInput?: BigNumber;
 | 
			
		||||
    outputAmountPerEth?: BigNumber;
 | 
			
		||||
    inputAmountPerEth?: BigNumber;
 | 
			
		||||
    excludedSources?: ERC20BridgeSource[];
 | 
			
		||||
    feeSchedule?: FeeSchedule;
 | 
			
		||||
    gasPrice: BigNumber;
 | 
			
		||||
}): Fill[][] {
 | 
			
		||||
    const { side } = opts;
 | 
			
		||||
    const excludedSources = opts.excludedSources || [];
 | 
			
		||||
    const feeSchedule = opts.feeSchedule || {};
 | 
			
		||||
    const orders = opts.orders || [];
 | 
			
		||||
    const dexQuotes = opts.dexQuotes || [];
 | 
			
		||||
    const outputAmountPerEth = opts.outputAmountPerEth || ZERO_AMOUNT;
 | 
			
		||||
@@ -35,15 +33,15 @@ export function createFills(opts: {
 | 
			
		||||
        opts.targetInput,
 | 
			
		||||
        outputAmountPerEth,
 | 
			
		||||
        inputAmountPerEth,
 | 
			
		||||
        feeSchedule,
 | 
			
		||||
        opts.gasPrice,
 | 
			
		||||
    );
 | 
			
		||||
    // Create DEX fills.
 | 
			
		||||
    const dexFills = dexQuotes.map(singleSourceSamples =>
 | 
			
		||||
        dexSamplesToFills(side, singleSourceSamples, outputAmountPerEth, inputAmountPerEth, feeSchedule),
 | 
			
		||||
        dexSamplesToFills(side, singleSourceSamples, outputAmountPerEth, inputAmountPerEth, opts.gasPrice),
 | 
			
		||||
    );
 | 
			
		||||
    return [...dexFills, nativeFills]
 | 
			
		||||
        .map(p => clipFillsToInput(p, opts.targetInput))
 | 
			
		||||
        .filter(fills => hasLiquidity(fills) && !excludedSources.includes(fills[0].source));
 | 
			
		||||
        .filter(fills => hasLiquidity(fills));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function clipFillsToInput(fills: Fill[], targetInput: BigNumber = POSITIVE_INF): Fill[] {
 | 
			
		||||
@@ -95,24 +93,34 @@ export function nativeOrdersToFills(
 | 
			
		||||
    targetInput: BigNumber = POSITIVE_INF,
 | 
			
		||||
    outputAmountPerEth: BigNumber,
 | 
			
		||||
    inputAmountPerEth: BigNumber,
 | 
			
		||||
    fees: FeeSchedule,
 | 
			
		||||
): Fill[] {
 | 
			
		||||
    gasPrice: BigNumber,
 | 
			
		||||
): NativeOrderFill[] {
 | 
			
		||||
    if (orders.length === 0) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    const sourcePathId = hexUtils.random();
 | 
			
		||||
    // Create a single path from all orders.
 | 
			
		||||
    let fills: Array<Fill & { adjustedRate: BigNumber }> = [];
 | 
			
		||||
    let fills: Array<NativeOrderFill & { adjustedRate: BigNumber }> = [];
 | 
			
		||||
    for (const o of orders) {
 | 
			
		||||
        const { fillableTakerAmount, fillableTakerFeeAmount, fillableMakerAmount, type } = o;
 | 
			
		||||
        const makerAmount = fillableMakerAmount;
 | 
			
		||||
        const takerAmount = fillableTakerAmount.plus(fillableTakerFeeAmount);
 | 
			
		||||
        const input = side === MarketOperation.Sell ? takerAmount : makerAmount;
 | 
			
		||||
        const output = side === MarketOperation.Sell ? makerAmount : takerAmount;
 | 
			
		||||
        const fee = fees[ERC20BridgeSource.Native] === undefined ? 0 : fees[ERC20BridgeSource.Native]!(o);
 | 
			
		||||
        const { fillableTakerAmount, fillableMakerAmount, type } = o;
 | 
			
		||||
        // TODO(lawrence): handle taker fees.
 | 
			
		||||
        if (o.fillableTakerFeeAmount.gt(0)) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        let input, output;
 | 
			
		||||
        if (side === MarketOperation.Sell) {
 | 
			
		||||
            input = fillableTakerAmount;
 | 
			
		||||
            output = fillableMakerAmount;
 | 
			
		||||
        } else {
 | 
			
		||||
            input = fillableMakerAmount;
 | 
			
		||||
            output = fillableTakerAmount;
 | 
			
		||||
        }
 | 
			
		||||
        const outputPenalty = ethToOutputAmount({
 | 
			
		||||
            input,
 | 
			
		||||
            output,
 | 
			
		||||
            inputAmountPerEth,
 | 
			
		||||
            outputAmountPerEth,
 | 
			
		||||
            ethAmount: fee,
 | 
			
		||||
            ethAmount: gasPrice.times(o.gasCost),
 | 
			
		||||
        });
 | 
			
		||||
        // targetInput can be less than the order size
 | 
			
		||||
        // whilst the penalty is constant, it affects the adjusted output
 | 
			
		||||
@@ -131,17 +139,21 @@ export function nativeOrdersToFills(
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        fills.push({
 | 
			
		||||
            type,
 | 
			
		||||
            sourcePathId,
 | 
			
		||||
            adjustedRate,
 | 
			
		||||
            adjustedOutput,
 | 
			
		||||
            adjustedRate,
 | 
			
		||||
            input: clippedInput,
 | 
			
		||||
            output: clippedOutput,
 | 
			
		||||
            flags: SOURCE_FLAGS[type === FillQuoteTransformerOrderType.Rfq ? 'RfqOrder' : 'LimitOrder'],
 | 
			
		||||
            index: 0, // TBD
 | 
			
		||||
            parent: undefined, // TBD
 | 
			
		||||
            source: ERC20BridgeSource.Native,
 | 
			
		||||
            type,
 | 
			
		||||
            fillData: { ...o },
 | 
			
		||||
            gasCost: o.gasCost,
 | 
			
		||||
            data: {
 | 
			
		||||
                order: o.order,
 | 
			
		||||
                signature: o.signature,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    // Sort by descending adjusted rate.
 | 
			
		||||
@@ -159,10 +171,10 @@ export function dexSamplesToFills(
 | 
			
		||||
    samples: DexSample[],
 | 
			
		||||
    outputAmountPerEth: BigNumber,
 | 
			
		||||
    inputAmountPerEth: BigNumber,
 | 
			
		||||
    fees: FeeSchedule,
 | 
			
		||||
): Fill[] {
 | 
			
		||||
    gasPrice: BigNumber,
 | 
			
		||||
): GenericBridgeFill[] {
 | 
			
		||||
    const sourcePathId = hexUtils.random();
 | 
			
		||||
    const fills: Fill[] = [];
 | 
			
		||||
    const fills: GenericBridgeFill[] = [];
 | 
			
		||||
    // Drop any non-zero entries. This can occur if the any fills on Kyber were UniswapReserves
 | 
			
		||||
    // We need not worry about Kyber fills going to UniswapReserve as the input amount
 | 
			
		||||
    // we fill is the same as we sampled. I.e we received [0,20,30] output from [1,2,3] input
 | 
			
		||||
@@ -171,10 +183,10 @@ export function dexSamplesToFills(
 | 
			
		||||
    for (let i = 0; i < nonzeroSamples.length; i++) {
 | 
			
		||||
        const sample = nonzeroSamples[i];
 | 
			
		||||
        const prevSample = i === 0 ? undefined : nonzeroSamples[i - 1];
 | 
			
		||||
        const { source, fillData } = sample;
 | 
			
		||||
        const { source, encodedFillData, metadata } = sample;
 | 
			
		||||
        const input = sample.input.minus(prevSample ? prevSample.input : 0);
 | 
			
		||||
        const output = sample.output.minus(prevSample ? prevSample.output : 0);
 | 
			
		||||
        const fee = fees[source] === undefined ? 0 : fees[source]!(sample.fillData) || 0;
 | 
			
		||||
        const fee = gasPrice.times(sample.gasCost);
 | 
			
		||||
        let penalty = ZERO_AMOUNT;
 | 
			
		||||
        if (i === 0) {
 | 
			
		||||
            // Only the first fill in a DEX path incurs a penalty.
 | 
			
		||||
@@ -194,11 +206,15 @@ export function dexSamplesToFills(
 | 
			
		||||
            output,
 | 
			
		||||
            adjustedOutput,
 | 
			
		||||
            source,
 | 
			
		||||
            fillData,
 | 
			
		||||
            type: FillQuoteTransformerOrderType.Bridge,
 | 
			
		||||
            gasCost: sample.gasCost,
 | 
			
		||||
            index: i,
 | 
			
		||||
            parent: i !== 0 ? fills[fills.length - 1] : undefined,
 | 
			
		||||
            flags: SOURCE_FLAGS[source],
 | 
			
		||||
            data: {
 | 
			
		||||
                ...metadata,
 | 
			
		||||
                encodedFillData,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    return fills;
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,16 +1,6 @@
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { Omit } from '../../types';
 | 
			
		||||
 | 
			
		||||
import { ZERO_AMOUNT } from './constants';
 | 
			
		||||
import { getTwoHopAdjustedRate } from './rate_utils';
 | 
			
		||||
import {
 | 
			
		||||
    DexSample,
 | 
			
		||||
    ExchangeProxyOverhead,
 | 
			
		||||
    FeeSchedule,
 | 
			
		||||
    MarketSideLiquidity,
 | 
			
		||||
    MultiHopFillData,
 | 
			
		||||
    TokenAdjacencyGraph,
 | 
			
		||||
} from './types';
 | 
			
		||||
 | 
			
		||||
@@ -30,49 +20,3 @@ export function getIntermediateTokens(
 | 
			
		||||
        token => token.toLowerCase() !== makerToken.toLowerCase() && token.toLowerCase() !== takerToken.toLowerCase(),
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the best two-hop quote and the fee-adjusted rate of that quote.
 | 
			
		||||
 */
 | 
			
		||||
export function getBestTwoHopQuote(
 | 
			
		||||
    marketSideLiquidity: Omit<MarketSideLiquidity, 'makerTokenDecimals' | 'takerTokenDecimals'>,
 | 
			
		||||
    feeSchedule?: FeeSchedule,
 | 
			
		||||
    exchangeProxyOverhead?: ExchangeProxyOverhead,
 | 
			
		||||
): { quote: DexSample<MultiHopFillData> | undefined; adjustedRate: BigNumber } {
 | 
			
		||||
    const { side, inputAmount, outputAmountPerEth, quotes } = marketSideLiquidity;
 | 
			
		||||
    const { twoHopQuotes } = quotes;
 | 
			
		||||
    // 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 = filteredQuotes
 | 
			
		||||
        .map(quote =>
 | 
			
		||||
            getTwoHopAdjustedRate(side, quote, inputAmount, outputAmountPerEth, feeSchedule, exchangeProxyOverhead),
 | 
			
		||||
        )
 | 
			
		||||
        .reduce(
 | 
			
		||||
            (prev, curr, i) =>
 | 
			
		||||
                curr.isGreaterThan(prev.adjustedRate) ? { adjustedRate: curr, quote: filteredQuotes[i] } : prev,
 | 
			
		||||
            {
 | 
			
		||||
                adjustedRate: getTwoHopAdjustedRate(
 | 
			
		||||
                    side,
 | 
			
		||||
                    filteredQuotes[0],
 | 
			
		||||
                    inputAmount,
 | 
			
		||||
                    outputAmountPerEth,
 | 
			
		||||
                    feeSchedule,
 | 
			
		||||
                    exchangeProxyOverhead,
 | 
			
		||||
                ),
 | 
			
		||||
                quote: filteredQuotes[0],
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
    return best;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,82 +1,19 @@
 | 
			
		||||
import { BridgeProtocol, encodeBridgeSourceId, FillQuoteTransformerOrderType } from '@0x/protocol-utils';
 | 
			
		||||
import { AbiEncoder, BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { AssetSwapperContractAddresses, MarketOperation } from '../../types';
 | 
			
		||||
import { Address, MarketOperation } from '../../types';
 | 
			
		||||
 | 
			
		||||
import { MAX_UINT256, ZERO_AMOUNT } from './constants';
 | 
			
		||||
import {
 | 
			
		||||
    AggregationError,
 | 
			
		||||
    BalancerFillData,
 | 
			
		||||
    BalancerV2FillData,
 | 
			
		||||
    BancorFillData,
 | 
			
		||||
    CollapsedFill,
 | 
			
		||||
    CurveFillData,
 | 
			
		||||
    DexSample,
 | 
			
		||||
    DODOFillData,
 | 
			
		||||
    CollapsedGenericBridgeFill,
 | 
			
		||||
    ERC20BridgeSource,
 | 
			
		||||
    FillData,
 | 
			
		||||
    FinalUniswapV3FillData,
 | 
			
		||||
    GenericRouterFillData,
 | 
			
		||||
    KyberDmmFillData,
 | 
			
		||||
    KyberFillData,
 | 
			
		||||
    LidoFillData,
 | 
			
		||||
    LiquidityProviderFillData,
 | 
			
		||||
    MakerPsmFillData,
 | 
			
		||||
    MooniswapFillData,
 | 
			
		||||
    MultiHopFillData,
 | 
			
		||||
    NativeCollapsedFill,
 | 
			
		||||
    NativeLimitOrderFillData,
 | 
			
		||||
    NativeRfqOrderFillData,
 | 
			
		||||
    OptimizedMarketBridgeOrder,
 | 
			
		||||
    OptimizedMarketOrder,
 | 
			
		||||
    OptimizedMarketOrderBase,
 | 
			
		||||
    OrderDomain,
 | 
			
		||||
    ShellFillData,
 | 
			
		||||
    UniswapV2FillData,
 | 
			
		||||
    UniswapV3FillData,
 | 
			
		||||
    CollapsedNativeOrderFill,
 | 
			
		||||
    OptimizedGenericBridgeOrder,
 | 
			
		||||
    OptimizedLimitOrder,
 | 
			
		||||
    OptimizedRfqOrder,
 | 
			
		||||
} from './types';
 | 
			
		||||
 | 
			
		||||
// tslint:disable completed-docs
 | 
			
		||||
 | 
			
		||||
export interface CreateOrderFromPathOpts {
 | 
			
		||||
    side: MarketOperation;
 | 
			
		||||
    inputToken: string;
 | 
			
		||||
    outputToken: string;
 | 
			
		||||
    orderDomain: OrderDomain;
 | 
			
		||||
    contractAddresses: AssetSwapperContractAddresses;
 | 
			
		||||
    bridgeSlippage: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function createOrdersFromTwoHopSample(
 | 
			
		||||
    sample: DexSample<MultiHopFillData>,
 | 
			
		||||
    opts: CreateOrderFromPathOpts,
 | 
			
		||||
): OptimizedMarketOrder[] {
 | 
			
		||||
    const [makerToken, takerToken] = getMakerTakerTokens(opts);
 | 
			
		||||
    const { firstHopSource, secondHopSource, intermediateToken } = sample.fillData;
 | 
			
		||||
    const firstHopFill: CollapsedFill = {
 | 
			
		||||
        sourcePathId: '',
 | 
			
		||||
        source: firstHopSource.source,
 | 
			
		||||
        type: FillQuoteTransformerOrderType.Bridge,
 | 
			
		||||
        input: opts.side === MarketOperation.Sell ? sample.input : ZERO_AMOUNT,
 | 
			
		||||
        output: opts.side === MarketOperation.Sell ? ZERO_AMOUNT : sample.output,
 | 
			
		||||
        subFills: [],
 | 
			
		||||
        fillData: firstHopSource.fillData,
 | 
			
		||||
    };
 | 
			
		||||
    const secondHopFill: CollapsedFill = {
 | 
			
		||||
        sourcePathId: '',
 | 
			
		||||
        source: secondHopSource.source,
 | 
			
		||||
        type: FillQuoteTransformerOrderType.Bridge,
 | 
			
		||||
        input: opts.side === MarketOperation.Sell ? MAX_UINT256 : sample.input,
 | 
			
		||||
        output: opts.side === MarketOperation.Sell ? sample.output : MAX_UINT256,
 | 
			
		||||
        subFills: [],
 | 
			
		||||
        fillData: secondHopSource.fillData,
 | 
			
		||||
    };
 | 
			
		||||
    return [
 | 
			
		||||
        createBridgeOrder(firstHopFill, intermediateToken, takerToken, opts.side),
 | 
			
		||||
        createBridgeOrder(secondHopFill, makerToken, intermediateToken, opts.side),
 | 
			
		||||
    ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): string {
 | 
			
		||||
    switch (source) {
 | 
			
		||||
        case ERC20BridgeSource.Balancer:
 | 
			
		||||
@@ -193,332 +130,51 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder): string {
 | 
			
		||||
    let bridgeData: string;
 | 
			
		||||
    if (
 | 
			
		||||
        order.source === ERC20BridgeSource.MultiHop ||
 | 
			
		||||
        order.source === ERC20BridgeSource.MultiBridge ||
 | 
			
		||||
        order.source === ERC20BridgeSource.Native
 | 
			
		||||
    ) {
 | 
			
		||||
        throw new Error('Invalid order to encode for Bridge Data');
 | 
			
		||||
    }
 | 
			
		||||
    const encoder = BRIDGE_ENCODERS[order.source];
 | 
			
		||||
 | 
			
		||||
    if (!encoder) {
 | 
			
		||||
        throw new Error(AggregationError.NoBridgeForSource);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (order.source) {
 | 
			
		||||
        case ERC20BridgeSource.Curve:
 | 
			
		||||
        case ERC20BridgeSource.CurveV2:
 | 
			
		||||
        case ERC20BridgeSource.Swerve:
 | 
			
		||||
        case ERC20BridgeSource.SnowSwap:
 | 
			
		||||
        case ERC20BridgeSource.Nerve:
 | 
			
		||||
        case ERC20BridgeSource.Belt:
 | 
			
		||||
        case ERC20BridgeSource.Ellipsis:
 | 
			
		||||
        case ERC20BridgeSource.Smoothy:
 | 
			
		||||
        case ERC20BridgeSource.Saddle:
 | 
			
		||||
        case ERC20BridgeSource.XSigma:
 | 
			
		||||
        case ERC20BridgeSource.FirebirdOneSwap:
 | 
			
		||||
        case ERC20BridgeSource.IronSwap:
 | 
			
		||||
        case ERC20BridgeSource.ACryptos:
 | 
			
		||||
            const curveFillData = (order as OptimizedMarketBridgeOrder<CurveFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([
 | 
			
		||||
                curveFillData.pool.poolAddress,
 | 
			
		||||
                curveFillData.pool.exchangeFunctionSelector,
 | 
			
		||||
                curveFillData.fromTokenIdx,
 | 
			
		||||
                curveFillData.toTokenIdx,
 | 
			
		||||
            ]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Balancer:
 | 
			
		||||
        case ERC20BridgeSource.Cream:
 | 
			
		||||
            const balancerFillData = (order as OptimizedMarketBridgeOrder<BalancerFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([balancerFillData.poolAddress]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.BalancerV2:
 | 
			
		||||
            const balancerV2FillData = (order as OptimizedMarketBridgeOrder<BalancerV2FillData>).fillData;
 | 
			
		||||
            const { vault, poolId } = balancerV2FillData;
 | 
			
		||||
            bridgeData = encoder.encode([vault, poolId]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Bancor:
 | 
			
		||||
            const bancorFillData = (order as OptimizedMarketBridgeOrder<BancorFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([bancorFillData.networkAddress, bancorFillData.path]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.UniswapV2:
 | 
			
		||||
        case ERC20BridgeSource.SushiSwap:
 | 
			
		||||
        case ERC20BridgeSource.CryptoCom:
 | 
			
		||||
        case ERC20BridgeSource.Linkswap:
 | 
			
		||||
        case ERC20BridgeSource.PancakeSwap:
 | 
			
		||||
        case ERC20BridgeSource.PancakeSwapV2:
 | 
			
		||||
        case ERC20BridgeSource.BakerySwap:
 | 
			
		||||
        case ERC20BridgeSource.ApeSwap:
 | 
			
		||||
        case ERC20BridgeSource.CafeSwap:
 | 
			
		||||
        case ERC20BridgeSource.CheeseSwap:
 | 
			
		||||
        case ERC20BridgeSource.JulSwap:
 | 
			
		||||
        case ERC20BridgeSource.QuickSwap:
 | 
			
		||||
        case ERC20BridgeSource.ComethSwap:
 | 
			
		||||
        case ERC20BridgeSource.Dfyn:
 | 
			
		||||
        case ERC20BridgeSource.WaultSwap:
 | 
			
		||||
        case ERC20BridgeSource.Polydex:
 | 
			
		||||
        case ERC20BridgeSource.ShibaSwap:
 | 
			
		||||
        case ERC20BridgeSource.JetSwap:
 | 
			
		||||
        case ERC20BridgeSource.Pangolin:
 | 
			
		||||
        case ERC20BridgeSource.TraderJoe:
 | 
			
		||||
        case ERC20BridgeSource.SpiritSwap:
 | 
			
		||||
        case ERC20BridgeSource.SpookySwap:
 | 
			
		||||
            const uniswapV2FillData = (order as OptimizedMarketBridgeOrder<UniswapV2FillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([uniswapV2FillData.router, uniswapV2FillData.tokenAddressPath]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Kyber:
 | 
			
		||||
            const kyberFillData = (order as OptimizedMarketBridgeOrder<KyberFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([kyberFillData.networkProxy, kyberFillData.hint]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Mooniswap:
 | 
			
		||||
            const mooniswapFillData = (order as OptimizedMarketBridgeOrder<MooniswapFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([mooniswapFillData.poolAddress]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Dodo:
 | 
			
		||||
            const dodoFillData = (order as OptimizedMarketBridgeOrder<DODOFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([
 | 
			
		||||
                dodoFillData.helperAddress,
 | 
			
		||||
                dodoFillData.poolAddress,
 | 
			
		||||
                dodoFillData.isSellBase,
 | 
			
		||||
            ]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.DodoV2:
 | 
			
		||||
            const dodoV2FillData = (order as OptimizedMarketBridgeOrder<DODOFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([dodoV2FillData.poolAddress, dodoV2FillData.isSellBase]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Shell:
 | 
			
		||||
        case ERC20BridgeSource.Component:
 | 
			
		||||
            const shellFillData = (order as OptimizedMarketBridgeOrder<ShellFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([shellFillData.poolAddress]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.LiquidityProvider:
 | 
			
		||||
            const lpFillData = (order as OptimizedMarketBridgeOrder<LiquidityProviderFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([lpFillData.poolAddress, tokenAddressEncoder.encode([order.takerToken])]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Uniswap:
 | 
			
		||||
            const uniFillData = (order as OptimizedMarketBridgeOrder<GenericRouterFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([uniFillData.router]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Eth2Dai:
 | 
			
		||||
            const oasisFillData = (order as OptimizedMarketBridgeOrder<GenericRouterFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([oasisFillData.router]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.MStable:
 | 
			
		||||
            const mStableFillData = (order as OptimizedMarketBridgeOrder<GenericRouterFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([mStableFillData.router]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.MakerPsm:
 | 
			
		||||
            const psmFillData = (order as OptimizedMarketBridgeOrder<MakerPsmFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([psmFillData.psmAddress, psmFillData.gemTokenAddress]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.UniswapV3:
 | 
			
		||||
            const uniswapV3FillData = (order as OptimizedMarketBridgeOrder<FinalUniswapV3FillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([uniswapV3FillData.router, uniswapV3FillData.uniswapPath]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.KyberDmm:
 | 
			
		||||
            const kyberDmmFillData = (order as OptimizedMarketBridgeOrder<KyberDmmFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([
 | 
			
		||||
                kyberDmmFillData.router,
 | 
			
		||||
                kyberDmmFillData.poolsPath,
 | 
			
		||||
                kyberDmmFillData.tokenAddressPath,
 | 
			
		||||
            ]);
 | 
			
		||||
            break;
 | 
			
		||||
        case ERC20BridgeSource.Lido:
 | 
			
		||||
            const lidoFillData = (order as OptimizedMarketBridgeOrder<LidoFillData>).fillData;
 | 
			
		||||
            bridgeData = encoder.encode([lidoFillData.stEthTokenAddress]);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            throw new Error(AggregationError.NoBridgeForSource);
 | 
			
		||||
    }
 | 
			
		||||
    return bridgeData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function createBridgeOrder(
 | 
			
		||||
    fill: CollapsedFill,
 | 
			
		||||
    makerToken: string,
 | 
			
		||||
    takerToken: string,
 | 
			
		||||
    side: MarketOperation,
 | 
			
		||||
): OptimizedMarketBridgeOrder {
 | 
			
		||||
    const [makerAmount, takerAmount] = getFillTokenAmounts(fill, side);
 | 
			
		||||
    fill: CollapsedGenericBridgeFill,
 | 
			
		||||
    inputToken: Address,
 | 
			
		||||
    outputToken: Address,
 | 
			
		||||
): OptimizedGenericBridgeOrder {
 | 
			
		||||
    return {
 | 
			
		||||
        makerToken,
 | 
			
		||||
        takerToken,
 | 
			
		||||
        makerAmount,
 | 
			
		||||
        takerAmount,
 | 
			
		||||
        fillData: createFinalBridgeOrderFillDataFromCollapsedFill(fill),
 | 
			
		||||
        inputToken,
 | 
			
		||||
        outputToken,
 | 
			
		||||
        inputAmount: fill.input,
 | 
			
		||||
        outputAmount: fill.output,
 | 
			
		||||
        fillData: fill.data,
 | 
			
		||||
        source: fill.source,
 | 
			
		||||
        sourcePathId: fill.sourcePathId,
 | 
			
		||||
        type: FillQuoteTransformerOrderType.Bridge,
 | 
			
		||||
        fills: [fill],
 | 
			
		||||
        gasCost: fill.gasCost,
 | 
			
		||||
        isFallback: fill.isFallback,
 | 
			
		||||
        ...((fill as any).metadata !== undefined ? { metadata: (fill as any).metadata } : {}),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createFinalBridgeOrderFillDataFromCollapsedFill(fill: CollapsedFill): FillData {
 | 
			
		||||
    switch (fill.source) {
 | 
			
		||||
        case ERC20BridgeSource.UniswapV3: {
 | 
			
		||||
            const fd = fill.fillData as UniswapV3FillData;
 | 
			
		||||
            return {
 | 
			
		||||
                router: fd.router,
 | 
			
		||||
                tokenAddressPath: fd.tokenAddressPath,
 | 
			
		||||
                uniswapPath: getBestUniswapV3PathForInputAmount(fd, fill.input),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    return fill.fillData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getBestUniswapV3PathForInputAmount(fillData: UniswapV3FillData, inputAmount: BigNumber): string {
 | 
			
		||||
    if (fillData.pathAmounts.length === 0) {
 | 
			
		||||
        throw new Error(`No Uniswap V3 paths`);
 | 
			
		||||
    }
 | 
			
		||||
    // Find the best path that can satisfy `inputAmount`.
 | 
			
		||||
    // Assumes `fillData.pathAmounts` is sorted ascending.
 | 
			
		||||
    for (const { inputAmount: pathInputAmount, uniswapPath } of fillData.pathAmounts) {
 | 
			
		||||
        if (pathInputAmount.gte(inputAmount)) {
 | 
			
		||||
            return uniswapPath;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return fillData.pathAmounts[fillData.pathAmounts.length - 1].uniswapPath;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getMakerTakerTokens(opts: CreateOrderFromPathOpts): [string, string] {
 | 
			
		||||
    const makerToken = opts.side === MarketOperation.Sell ? opts.outputToken : opts.inputToken;
 | 
			
		||||
    const takerToken = opts.side === MarketOperation.Sell ? opts.inputToken : opts.outputToken;
 | 
			
		||||
export function getMakerTakerTokens(side: MarketOperation, inputToken: Address, outputToken: Address): [Address, Address] {
 | 
			
		||||
    const makerToken = side === MarketOperation.Sell ? outputToken : inputToken;
 | 
			
		||||
    const takerToken = side === MarketOperation.Sell ? inputToken : outputToken;
 | 
			
		||||
    return [makerToken, takerToken];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const poolEncoder = AbiEncoder.create([{ name: 'poolAddress', type: 'address' }]);
 | 
			
		||||
const curveEncoder = AbiEncoder.create([
 | 
			
		||||
    { name: 'curveAddress', type: 'address' },
 | 
			
		||||
    { name: 'exchangeFunctionSelector', type: 'bytes4' },
 | 
			
		||||
    { name: 'fromTokenIdx', type: 'int128' },
 | 
			
		||||
    { name: 'toTokenIdx', type: 'int128' },
 | 
			
		||||
]);
 | 
			
		||||
const makerPsmEncoder = AbiEncoder.create([
 | 
			
		||||
    { name: 'psmAddress', type: 'address' },
 | 
			
		||||
    { name: 'gemTokenAddress', type: 'address' },
 | 
			
		||||
]);
 | 
			
		||||
const balancerV2Encoder = AbiEncoder.create([
 | 
			
		||||
    { name: 'vault', type: 'address' },
 | 
			
		||||
    { name: 'poolId', type: 'bytes32' },
 | 
			
		||||
]);
 | 
			
		||||
const routerAddressPathEncoder = AbiEncoder.create('(address,address[])');
 | 
			
		||||
const tokenAddressEncoder = AbiEncoder.create([{ name: 'tokenAddress', type: 'address' }]);
 | 
			
		||||
 | 
			
		||||
export const BRIDGE_ENCODERS: {
 | 
			
		||||
    [key in Exclude<
 | 
			
		||||
        ERC20BridgeSource,
 | 
			
		||||
        ERC20BridgeSource.Native | ERC20BridgeSource.MultiHop | ERC20BridgeSource.MultiBridge
 | 
			
		||||
    >]: AbiEncoder.DataType;
 | 
			
		||||
} = {
 | 
			
		||||
    [ERC20BridgeSource.LiquidityProvider]: AbiEncoder.create([
 | 
			
		||||
        { name: 'provider', type: 'address' },
 | 
			
		||||
        { name: 'data', type: 'bytes' },
 | 
			
		||||
    ]),
 | 
			
		||||
    [ERC20BridgeSource.Kyber]: AbiEncoder.create([
 | 
			
		||||
        { name: 'kyberNetworkProxy', type: 'address' },
 | 
			
		||||
        { name: 'hint', type: 'bytes' },
 | 
			
		||||
    ]),
 | 
			
		||||
    [ERC20BridgeSource.Dodo]: AbiEncoder.create([
 | 
			
		||||
        { name: 'helper', type: 'address' },
 | 
			
		||||
        { name: 'poolAddress', type: 'address' },
 | 
			
		||||
        { name: 'isSellBase', type: 'bool' },
 | 
			
		||||
    ]),
 | 
			
		||||
    [ERC20BridgeSource.DodoV2]: AbiEncoder.create([
 | 
			
		||||
        { name: 'poolAddress', type: 'address' },
 | 
			
		||||
        { name: 'isSellBase', type: 'bool' },
 | 
			
		||||
    ]),
 | 
			
		||||
    // Curve like
 | 
			
		||||
    [ERC20BridgeSource.Curve]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.CurveV2]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Swerve]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.SnowSwap]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Nerve]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Belt]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Ellipsis]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Smoothy]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Saddle]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.XSigma]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.FirebirdOneSwap]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.IronSwap]: curveEncoder,
 | 
			
		||||
    [ERC20BridgeSource.ACryptos]: curveEncoder,
 | 
			
		||||
    // UniswapV2 like, (router, address[])
 | 
			
		||||
    [ERC20BridgeSource.Bancor]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.UniswapV2]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.SushiSwap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.CryptoCom]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Linkswap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.ShibaSwap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Pangolin]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.TraderJoe]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.SpiritSwap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.SpookySwap]: routerAddressPathEncoder,
 | 
			
		||||
    // BSC
 | 
			
		||||
    [ERC20BridgeSource.PancakeSwap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.PancakeSwapV2]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.BakerySwap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.ApeSwap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.CafeSwap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.CheeseSwap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.JulSwap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.WaultSwap]: routerAddressPathEncoder,
 | 
			
		||||
    // Polygon
 | 
			
		||||
    [ERC20BridgeSource.QuickSwap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.ComethSwap]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Dfyn]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Polydex]: routerAddressPathEncoder,
 | 
			
		||||
    [ERC20BridgeSource.JetSwap]: routerAddressPathEncoder,
 | 
			
		||||
    // Generic pools
 | 
			
		||||
    [ERC20BridgeSource.Shell]: poolEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Component]: poolEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Mooniswap]: poolEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Eth2Dai]: poolEncoder,
 | 
			
		||||
    [ERC20BridgeSource.MStable]: poolEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Balancer]: poolEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Cream]: poolEncoder,
 | 
			
		||||
    [ERC20BridgeSource.Uniswap]: poolEncoder,
 | 
			
		||||
    // Custom integrations
 | 
			
		||||
    [ERC20BridgeSource.MakerPsm]: makerPsmEncoder,
 | 
			
		||||
    [ERC20BridgeSource.BalancerV2]: balancerV2Encoder,
 | 
			
		||||
    [ERC20BridgeSource.UniswapV3]: AbiEncoder.create([
 | 
			
		||||
        { name: 'router', type: 'address' },
 | 
			
		||||
        { name: 'path', type: 'bytes' },
 | 
			
		||||
    ]),
 | 
			
		||||
    [ERC20BridgeSource.KyberDmm]: AbiEncoder.create('(address,address[],address[])'),
 | 
			
		||||
    [ERC20BridgeSource.Lido]: AbiEncoder.create('(address)'),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function getFillTokenAmounts(fill: CollapsedFill, side: MarketOperation): [BigNumber, BigNumber] {
 | 
			
		||||
    return [
 | 
			
		||||
        // Maker asset amount.
 | 
			
		||||
        side === MarketOperation.Sell ? fill.output.integerValue(BigNumber.ROUND_DOWN) : fill.input,
 | 
			
		||||
        // Taker asset amount.
 | 
			
		||||
        side === MarketOperation.Sell ? fill.input : fill.output.integerValue(BigNumber.ROUND_UP),
 | 
			
		||||
    ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function createNativeOptimizedOrder(
 | 
			
		||||
    fill: NativeCollapsedFill,
 | 
			
		||||
    fill: CollapsedNativeOrderFill,
 | 
			
		||||
    side: MarketOperation,
 | 
			
		||||
): OptimizedMarketOrderBase<NativeLimitOrderFillData> | OptimizedMarketOrderBase<NativeRfqOrderFillData> {
 | 
			
		||||
    const fillData = fill.fillData;
 | 
			
		||||
    const [makerAmount, takerAmount] = getFillTokenAmounts(fill, side);
 | 
			
		||||
    const base = {
 | 
			
		||||
        type: fill.type,
 | 
			
		||||
        source: ERC20BridgeSource.Native,
 | 
			
		||||
        makerToken: fillData.order.makerToken,
 | 
			
		||||
        takerToken: fillData.order.takerToken,
 | 
			
		||||
        makerAmount,
 | 
			
		||||
        takerAmount,
 | 
			
		||||
        fills: [fill],
 | 
			
		||||
        fillData,
 | 
			
		||||
    };
 | 
			
		||||
    return fill.type === FillQuoteTransformerOrderType.Rfq
 | 
			
		||||
        ? { ...base, type: FillQuoteTransformerOrderType.Rfq, fillData: fillData as NativeRfqOrderFillData }
 | 
			
		||||
        : { ...base, type: FillQuoteTransformerOrderType.Limit, fillData: fillData as NativeLimitOrderFillData };
 | 
			
		||||
): OptimizedLimitOrder | OptimizedRfqOrder {
 | 
			
		||||
    throw new Error(`No implementado`);
 | 
			
		||||
    // const fillData = fill.fillData;
 | 
			
		||||
    // const [makerAmount, takerAmount] = getFillTokenAmounts(fill, side);
 | 
			
		||||
    // const base = {
 | 
			
		||||
    //     type: fill.type,
 | 
			
		||||
    //     source: ERC20BridgeSource.Native,
 | 
			
		||||
    //     makerToken: fillData.order.makerToken,
 | 
			
		||||
    //     takerToken: fillData.order.takerToken,
 | 
			
		||||
    //     makerAmount,
 | 
			
		||||
    //     takerAmount,
 | 
			
		||||
    //     fills: [fill],
 | 
			
		||||
    //     fillData,
 | 
			
		||||
    // };
 | 
			
		||||
    // return fill.type === FillQuoteTransformerOrderType.Rfq
 | 
			
		||||
    //     ? { ...base, type: FillQuoteTransformerOrderType.Rfq, fillData: fillData as NativeRfqOrderFillData }
 | 
			
		||||
    //     : { ...base, type: FillQuoteTransformerOrderType.Limit, fillData: fillData as NativeLimitOrderFillData };
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,19 @@
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { MarketOperation } from '../../types';
 | 
			
		||||
import { Address, MarketOperation } from '../../types';
 | 
			
		||||
 | 
			
		||||
import { POSITIVE_INF, ZERO_AMOUNT } from './constants';
 | 
			
		||||
import { ethToOutputAmount } from './fills';
 | 
			
		||||
import { createBridgeOrder, createNativeOptimizedOrder, CreateOrderFromPathOpts, getMakerTakerTokens } from './orders';
 | 
			
		||||
import { createBridgeOrder, createNativeOptimizedOrder } from './orders';
 | 
			
		||||
import { getCompleteRate, getRate } from './rate_utils';
 | 
			
		||||
import {
 | 
			
		||||
    CollapsedGenericBridgeFill,
 | 
			
		||||
    CollapsedFill,
 | 
			
		||||
    CollapsedNativeOrderFill,
 | 
			
		||||
    ERC20BridgeSource,
 | 
			
		||||
    ExchangeProxyOverhead,
 | 
			
		||||
    Fill,
 | 
			
		||||
    NativeCollapsedFill,
 | 
			
		||||
    OptimizedMarketOrder,
 | 
			
		||||
    OptimizedOrder,
 | 
			
		||||
} from './types';
 | 
			
		||||
 | 
			
		||||
// tslint:disable: prefer-for-of no-bitwise completed-docs
 | 
			
		||||
@@ -38,10 +39,11 @@ export const DEFAULT_PATH_PENALTY_OPTS: PathPenaltyOpts = {
 | 
			
		||||
 | 
			
		||||
export class Path {
 | 
			
		||||
    public collapsedFills?: ReadonlyArray<CollapsedFill>;
 | 
			
		||||
    public orders?: OptimizedMarketOrder[];
 | 
			
		||||
    public orders?: OptimizedOrder[];
 | 
			
		||||
    public sourceFlags: bigint = BigInt(0);
 | 
			
		||||
    protected _size: PathSize = { input: ZERO_AMOUNT, output: ZERO_AMOUNT };
 | 
			
		||||
    protected _adjustedSize: PathSize = { input: ZERO_AMOUNT, output: ZERO_AMOUNT };
 | 
			
		||||
    private _fallbackFillsStartIndex: number = 0;
 | 
			
		||||
 | 
			
		||||
    public static create(
 | 
			
		||||
        side: MarketOperation,
 | 
			
		||||
@@ -107,33 +109,25 @@ export class Path {
 | 
			
		||||
            // Add the fills to the end that aren't already included
 | 
			
		||||
            ...fallback.fills.filter(f => !otherFillIds.includes(fillToFillId(f))),
 | 
			
		||||
        ];
 | 
			
		||||
        this._fallbackFillsStartIndex = nativeFills.length + otherFills.length;
 | 
			
		||||
        // Recompute the source flags
 | 
			
		||||
        this.sourceFlags = this.fills.reduce((flags, fill) => flags | fill.flags, BigInt(0));
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public collapse(opts: CreateOrderFromPathOpts): CollapsedPath {
 | 
			
		||||
        const [makerToken, takerToken] = getMakerTakerTokens(opts);
 | 
			
		||||
    public collapse(opts: { side: MarketOperation, inputToken: Address; outputToken: Address; }): CollapsedPath {
 | 
			
		||||
        const collapsedFills = this.collapsedFills === undefined ? this._collapseFills() : this.collapsedFills;
 | 
			
		||||
        this.orders = [];
 | 
			
		||||
        for (let i = 0; i < collapsedFills.length; ) {
 | 
			
		||||
        for (let i = 0; i < collapsedFills.length; ++i) {
 | 
			
		||||
            if (collapsedFills[i].source === ERC20BridgeSource.Native) {
 | 
			
		||||
                this.orders.push(createNativeOptimizedOrder(collapsedFills[i] as NativeCollapsedFill, opts.side));
 | 
			
		||||
                ++i;
 | 
			
		||||
                this.orders.push(createNativeOptimizedOrder(collapsedFills[i] as CollapsedNativeOrderFill, opts.side));
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            // If there are contiguous bridge orders, we can batch them together.
 | 
			
		||||
            // TODO jacob pretty sure this is from DFB and we can remove
 | 
			
		||||
            const contiguousBridgeFills = [collapsedFills[i]];
 | 
			
		||||
            for (let j = i + 1; j < collapsedFills.length; ++j) {
 | 
			
		||||
                if (collapsedFills[j].source === ERC20BridgeSource.Native) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                contiguousBridgeFills.push(collapsedFills[j]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.orders.push(createBridgeOrder(contiguousBridgeFills[0], makerToken, takerToken, opts.side));
 | 
			
		||||
            i += 1;
 | 
			
		||||
            this.orders.push(createBridgeOrder(
 | 
			
		||||
                collapsedFills[i] as CollapsedGenericBridgeFill,
 | 
			
		||||
                opts.inputToken,
 | 
			
		||||
                opts.outputToken,
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
        return this as CollapsedPath;
 | 
			
		||||
    }
 | 
			
		||||
@@ -214,7 +208,7 @@ export class Path {
 | 
			
		||||
        return input.gte(this.targetInput);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public isValid(skipDuplicateCheck: boolean = false): boolean {
 | 
			
		||||
    public isValid(quick: boolean = false): boolean {
 | 
			
		||||
        for (let i = 0; i < this.fills.length; ++i) {
 | 
			
		||||
            // Fill must immediately follow its parent.
 | 
			
		||||
            if (this.fills[i].parent) {
 | 
			
		||||
@@ -222,8 +216,9 @@ export class Path {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (!skipDuplicateCheck) {
 | 
			
		||||
            if (!quick) {
 | 
			
		||||
                // Fill must not be duplicated.
 | 
			
		||||
                // Fills must all have the same input and output tokens.
 | 
			
		||||
                for (let j = 0; j < i; ++j) {
 | 
			
		||||
                    if (this.fills[i] === this.fills[j]) {
 | 
			
		||||
                        return false;
 | 
			
		||||
@@ -249,7 +244,7 @@ export class Path {
 | 
			
		||||
 | 
			
		||||
    private _collapseFills(): ReadonlyArray<CollapsedFill> {
 | 
			
		||||
        this.collapsedFills = [];
 | 
			
		||||
        for (const fill of this.fills) {
 | 
			
		||||
        for (const [i, fill] of this.fills.entries()) {
 | 
			
		||||
            const source = fill.source;
 | 
			
		||||
            if (this.collapsedFills.length !== 0 && source !== ERC20BridgeSource.Native) {
 | 
			
		||||
                const prevFill = this.collapsedFills[this.collapsedFills.length - 1];
 | 
			
		||||
@@ -257,8 +252,9 @@ export class Path {
 | 
			
		||||
                if (prevFill.sourcePathId === fill.sourcePathId) {
 | 
			
		||||
                    prevFill.input = prevFill.input.plus(fill.input);
 | 
			
		||||
                    prevFill.output = prevFill.output.plus(fill.output);
 | 
			
		||||
                    prevFill.fillData = fill.fillData;
 | 
			
		||||
                    prevFill.data = fill.data;
 | 
			
		||||
                    prevFill.subFills.push(fill);
 | 
			
		||||
                    prevFill.gasCost;
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -266,10 +262,12 @@ export class Path {
 | 
			
		||||
                sourcePathId: fill.sourcePathId,
 | 
			
		||||
                source: fill.source,
 | 
			
		||||
                type: fill.type,
 | 
			
		||||
                fillData: fill.fillData,
 | 
			
		||||
                data: fill.data,
 | 
			
		||||
                input: fill.input,
 | 
			
		||||
                output: fill.output,
 | 
			
		||||
                subFills: [fill],
 | 
			
		||||
                gasCost: fill.gasCost,
 | 
			
		||||
                isFallback: this._fallbackFillsStartIndex > 0 ? i >= this._fallbackFillsStartIndex : false,
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        return this.collapsedFills;
 | 
			
		||||
@@ -296,5 +294,5 @@ export class Path {
 | 
			
		||||
 | 
			
		||||
export interface CollapsedPath extends Path {
 | 
			
		||||
    readonly collapsedFills: ReadonlyArray<CollapsedFill>;
 | 
			
		||||
    readonly orders: OptimizedMarketOrder[];
 | 
			
		||||
    readonly orders: OptimizedOrder[];
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,13 +6,14 @@ import * as _ from 'lodash';
 | 
			
		||||
import { performance } from 'perf_hooks';
 | 
			
		||||
 | 
			
		||||
import { DEFAULT_INFO_LOGGER } from '../../constants';
 | 
			
		||||
import { MarketOperation, NativeOrderWithFillableAmounts } from '../../types';
 | 
			
		||||
import { NativeOrderWithFillableAmounts } from '../native_orders';
 | 
			
		||||
import { MarketOperation } from '../../types';
 | 
			
		||||
import { VIP_ERC20_BRIDGE_SOURCES_BY_CHAIN_ID } from '../market_operation_utils/constants';
 | 
			
		||||
 | 
			
		||||
import { dexSamplesToFills, ethToOutputAmount, nativeOrdersToFills } from './fills';
 | 
			
		||||
import { DEFAULT_PATH_PENALTY_OPTS, Path, PathPenaltyOpts } from './path';
 | 
			
		||||
import { getRate } from './rate_utils';
 | 
			
		||||
import { DexSample, ERC20BridgeSource, FeeSchedule, Fill, FillData } from './types';
 | 
			
		||||
import { DexSample, ERC20BridgeSource, Fill } from './types';
 | 
			
		||||
 | 
			
		||||
// tslint:disable: prefer-for-of custom-no-magic-numbers completed-docs no-bitwise
 | 
			
		||||
 | 
			
		||||
@@ -42,11 +43,11 @@ function calculateOuputFee(
 | 
			
		||||
    sampleOrNativeOrder: DexSample | NativeOrderWithFillableAmounts,
 | 
			
		||||
    outputAmountPerEth: BigNumber,
 | 
			
		||||
    inputAmountPerEth: BigNumber,
 | 
			
		||||
    fees: FeeSchedule,
 | 
			
		||||
    gasPrice: BigNumber,
 | 
			
		||||
): BigNumber {
 | 
			
		||||
    if (isDexSample(sampleOrNativeOrder)) {
 | 
			
		||||
        const { input, output, source, fillData } = sampleOrNativeOrder;
 | 
			
		||||
        const fee = fees[source]?.(fillData) || 0;
 | 
			
		||||
        const { input, output } = sampleOrNativeOrder;
 | 
			
		||||
        const fee = gasPrice.times(sampleOrNativeOrder.gasCost);
 | 
			
		||||
        const outputFee = ethToOutputAmount({
 | 
			
		||||
            input,
 | 
			
		||||
            output,
 | 
			
		||||
@@ -57,13 +58,12 @@ function calculateOuputFee(
 | 
			
		||||
        return outputFee;
 | 
			
		||||
    } else {
 | 
			
		||||
        const { input, output } = nativeOrderToNormalizedAmounts(side, sampleOrNativeOrder);
 | 
			
		||||
        const fee = fees[ERC20BridgeSource.Native]?.(sampleOrNativeOrder) || 0;
 | 
			
		||||
        const outputFee = ethToOutputAmount({
 | 
			
		||||
            input,
 | 
			
		||||
            output,
 | 
			
		||||
            inputAmountPerEth,
 | 
			
		||||
            outputAmountPerEth,
 | 
			
		||||
            ethAmount: fee,
 | 
			
		||||
            ethAmount: gasPrice.times((sampleOrNativeOrder as NativeOrderWithFillableAmounts).gasCost),
 | 
			
		||||
        });
 | 
			
		||||
        return outputFee;
 | 
			
		||||
    }
 | 
			
		||||
@@ -90,10 +90,10 @@ function findRoutesAndCreateOptimalPath(
 | 
			
		||||
    nativeOrders: NativeOrderWithFillableAmounts[],
 | 
			
		||||
    input: BigNumber,
 | 
			
		||||
    opts: PathPenaltyOpts,
 | 
			
		||||
    fees: FeeSchedule,
 | 
			
		||||
    gasPrice: BigNumber,
 | 
			
		||||
): Path | undefined {
 | 
			
		||||
    const createFill = (sample: DexSample) =>
 | 
			
		||||
        dexSamplesToFills(side, [sample], opts.outputAmountPerEth, opts.inputAmountPerEth, fees)[0];
 | 
			
		||||
        dexSamplesToFills(side, [sample], opts.outputAmountPerEth, opts.inputAmountPerEth, gasPrice)[0];
 | 
			
		||||
    // Track sample id's to integers (required by rust router)
 | 
			
		||||
    const sampleIdLookup: { [key: string]: number } = {};
 | 
			
		||||
    let sampleIdCounter = 0;
 | 
			
		||||
@@ -135,7 +135,7 @@ function findRoutesAndCreateOptimalPath(
 | 
			
		||||
                memo.inputs.push(sample.input.integerValue().toNumber());
 | 
			
		||||
                memo.outputs.push(sample.output.integerValue().toNumber());
 | 
			
		||||
                memo.outputFees.push(
 | 
			
		||||
                    calculateOuputFee(side, sample, opts.outputAmountPerEth, opts.inputAmountPerEth, fees)
 | 
			
		||||
                    calculateOuputFee(side, sample, opts.outputAmountPerEth, opts.inputAmountPerEth, gasPrice)
 | 
			
		||||
                        .integerValue()
 | 
			
		||||
                        .toNumber(),
 | 
			
		||||
                );
 | 
			
		||||
@@ -183,7 +183,7 @@ function findRoutesAndCreateOptimalPath(
 | 
			
		||||
            normalizedOrderOutput.integerValue().toNumber(),
 | 
			
		||||
        ];
 | 
			
		||||
        // NOTE: same fee no matter if full or partial fill
 | 
			
		||||
        const fee = calculateOuputFee(side, nativeOrder, opts.outputAmountPerEth, opts.inputAmountPerEth, fees)
 | 
			
		||||
        const fee = calculateOuputFee(side, nativeOrder, opts.outputAmountPerEth, opts.inputAmountPerEth, gasPrice)
 | 
			
		||||
            .integerValue()
 | 
			
		||||
            .toNumber();
 | 
			
		||||
        const outputFees = [fee, fee, fee];
 | 
			
		||||
@@ -250,7 +250,7 @@ function findRoutesAndCreateOptimalPath(
 | 
			
		||||
                rustInputAdjusted,
 | 
			
		||||
                opts.outputAmountPerEth,
 | 
			
		||||
                opts.inputAmountPerEth,
 | 
			
		||||
                fees,
 | 
			
		||||
               gasPrice,
 | 
			
		||||
            )[0];
 | 
			
		||||
            // NOTE: For Limit/RFQ orders we are done here. No need to scale output
 | 
			
		||||
            adjustedFills.push(nativeFill);
 | 
			
		||||
@@ -259,7 +259,7 @@ function findRoutesAndCreateOptimalPath(
 | 
			
		||||
 | 
			
		||||
        // NOTE: For DexSamples only
 | 
			
		||||
        let fill = createFill(current);
 | 
			
		||||
        const routeSamples = routeSamplesAndNativeOrders as Array<DexSample<FillData>>;
 | 
			
		||||
        const routeSamples = routeSamplesAndNativeOrders as Array<DexSample>;
 | 
			
		||||
        // Descend to approach a closer fill for fillData which may not be consistent
 | 
			
		||||
        // throughout the path (UniswapV3) and for a closer guesstimate at
 | 
			
		||||
        // gas used
 | 
			
		||||
@@ -321,7 +321,7 @@ export function findOptimalRustPathFromSamples(
 | 
			
		||||
    nativeOrders: NativeOrderWithFillableAmounts[],
 | 
			
		||||
    input: BigNumber,
 | 
			
		||||
    opts: PathPenaltyOpts,
 | 
			
		||||
    fees: FeeSchedule,
 | 
			
		||||
    gasPrice: BigNumber,
 | 
			
		||||
    chainId: ChainId,
 | 
			
		||||
): Path | undefined {
 | 
			
		||||
    const before = performance.now();
 | 
			
		||||
@@ -331,7 +331,7 @@ export function findOptimalRustPathFromSamples(
 | 
			
		||||
            'Rust router total routing performance',
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    const allSourcesPath = findRoutesAndCreateOptimalPath(side, samples, nativeOrders, input, opts, fees);
 | 
			
		||||
    const allSourcesPath = findRoutesAndCreateOptimalPath(side, samples, nativeOrders, input, opts, gasPrice);
 | 
			
		||||
    if (!allSourcesPath) {
 | 
			
		||||
        return undefined;
 | 
			
		||||
    }
 | 
			
		||||
@@ -345,7 +345,7 @@ export function findOptimalRustPathFromSamples(
 | 
			
		||||
        const vipSourcesSamples = samples.filter(s => s[0] && vipSourcesSet.has(s[0].source));
 | 
			
		||||
 | 
			
		||||
        if (vipSourcesSamples.length > 0) {
 | 
			
		||||
            const vipSourcesPath = findRoutesAndCreateOptimalPath(side, vipSourcesSamples, [], input, opts, fees);
 | 
			
		||||
            const vipSourcesPath = findRoutesAndCreateOptimalPath(side, vipSourcesSamples, [], input, opts, gasPrice);
 | 
			
		||||
 | 
			
		||||
            const { input: allSourcesInput, output: allSourcesOutput } = allSourcesPath.adjustedSize();
 | 
			
		||||
            // NOTE: For sell quotes input is the taker asset and for buy quotes input is the maker asset
 | 
			
		||||
@@ -381,7 +381,7 @@ export async function findOptimalPathJSAsync(
 | 
			
		||||
): Promise<Path | undefined> {
 | 
			
		||||
    // Sort fill arrays by descending adjusted completed rate.
 | 
			
		||||
    // Remove any paths which cannot impact the optimal path
 | 
			
		||||
    const sortedPaths = reducePaths(fillsToSortedPaths(fills, side, targetInput, opts), side);
 | 
			
		||||
    const sortedPaths = reducePaths(fillsToSortedPaths(fills, side, targetInput, opts));
 | 
			
		||||
    if (sortedPaths.length === 0) {
 | 
			
		||||
        return undefined;
 | 
			
		||||
    }
 | 
			
		||||
@@ -420,7 +420,7 @@ export function fillsToSortedPaths(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove paths which have no impact on the optimal path
 | 
			
		||||
export function reducePaths(sortedPaths: Path[], side: MarketOperation): Path[] {
 | 
			
		||||
export function reducePaths(sortedPaths: Path[]): Path[] {
 | 
			
		||||
    // Any path which has a min rate that is less than the best adjusted completed rate has no chance of improving
 | 
			
		||||
    // the overall route.
 | 
			
		||||
    const bestNonNativeCompletePath = sortedPaths.filter(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,149 +0,0 @@
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
/**
 | 
			
		||||
 * This has been copied from https://github.com/balancer-labs/balancer-sor/blob/john/rc2/src/helpers.ts.
 | 
			
		||||
 * Still awaiting V2 support for @balancer-labs/sor, once full V2 support is shipped we can upgrade sor and delete this file
 | 
			
		||||
 */
 | 
			
		||||
export const parsePoolData = (
 | 
			
		||||
    directPools: SubGraphPoolDictionary,
 | 
			
		||||
    tokenIn: string,
 | 
			
		||||
    tokenOut: string,
 | 
			
		||||
    mostLiquidPoolsFirstHop: SubGraphPool[] = [],
 | 
			
		||||
    mostLiquidPoolsSecondHop: SubGraphPool[] = [],
 | 
			
		||||
    hopTokens: string[] = [],
 | 
			
		||||
): [SubGraphPoolDictionary, Path[]] => {
 | 
			
		||||
    const pathDataList: Path[] = [];
 | 
			
		||||
    const pools: SubGraphPoolDictionary = {};
 | 
			
		||||
 | 
			
		||||
    // First add direct pair paths
 | 
			
		||||
    // tslint:disable-next-line:forin
 | 
			
		||||
    for (const idKey in directPools) {
 | 
			
		||||
        const p: SubGraphPool = directPools[idKey];
 | 
			
		||||
        // Add pool to the set with all pools (only adds if it's still not present in dict)
 | 
			
		||||
        pools[idKey] = p;
 | 
			
		||||
 | 
			
		||||
        const swap: Swap = {
 | 
			
		||||
            pool: p.id,
 | 
			
		||||
            tokenIn,
 | 
			
		||||
            tokenOut,
 | 
			
		||||
            tokenInDecimals: 18, // Placeholder for actual decimals
 | 
			
		||||
            tokenOutDecimals: 18,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const path: Path = {
 | 
			
		||||
            id: p.id,
 | 
			
		||||
            swaps: [swap],
 | 
			
		||||
        };
 | 
			
		||||
        pathDataList.push(path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Now add multi-hop paths.
 | 
			
		||||
    // mostLiquidPoolsFirstHop and mostLiquidPoolsSecondHop always has the same
 | 
			
		||||
    // lengh of hopTokens
 | 
			
		||||
    for (let i = 0; i < hopTokens.length; i++) {
 | 
			
		||||
        // Add pools to the set with all pools (only adds if it's still not present in dict)
 | 
			
		||||
        pools[mostLiquidPoolsFirstHop[i].id] = mostLiquidPoolsFirstHop[i];
 | 
			
		||||
        pools[mostLiquidPoolsSecondHop[i].id] = mostLiquidPoolsSecondHop[i];
 | 
			
		||||
 | 
			
		||||
        const swap1: Swap = {
 | 
			
		||||
            pool: mostLiquidPoolsFirstHop[i].id,
 | 
			
		||||
            tokenIn,
 | 
			
		||||
            tokenOut: hopTokens[i],
 | 
			
		||||
            tokenInDecimals: 18, // Placeholder for actual decimals
 | 
			
		||||
            tokenOutDecimals: 18,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const swap2: Swap = {
 | 
			
		||||
            pool: mostLiquidPoolsSecondHop[i].id,
 | 
			
		||||
            tokenIn: hopTokens[i],
 | 
			
		||||
            tokenOut,
 | 
			
		||||
            tokenInDecimals: 18, // Placeholder for actual decimals
 | 
			
		||||
            tokenOutDecimals: 18,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const path: Path = {
 | 
			
		||||
            id: mostLiquidPoolsFirstHop[i].id + mostLiquidPoolsSecondHop[i].id, // Path id is the concatenation of the ids of poolFirstHop and poolSecondHop
 | 
			
		||||
            swaps: [swap1, swap2],
 | 
			
		||||
        };
 | 
			
		||||
        pathDataList.push(path);
 | 
			
		||||
    }
 | 
			
		||||
    return [pools, pathDataList];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface SubGraphPool {
 | 
			
		||||
    id: string;
 | 
			
		||||
    swapFee: string;
 | 
			
		||||
    totalWeight: string;
 | 
			
		||||
    totalShares: string;
 | 
			
		||||
    tokens: SubGraphToken[];
 | 
			
		||||
    tokensList: string[];
 | 
			
		||||
    poolType?: string;
 | 
			
		||||
 | 
			
		||||
    // Only for stable pools
 | 
			
		||||
    amp: string;
 | 
			
		||||
 | 
			
		||||
    // Only for element pools
 | 
			
		||||
    lpShares?: BigNumber;
 | 
			
		||||
    time?: BigNumber;
 | 
			
		||||
    principalToken?: string;
 | 
			
		||||
    baseToken?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface SubGraphPoolDictionary {
 | 
			
		||||
    [poolId: string]: SubGraphPool;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface SubGraphToken {
 | 
			
		||||
    address: string;
 | 
			
		||||
    balance: string;
 | 
			
		||||
    decimals: string | number;
 | 
			
		||||
    // Stable & Element field
 | 
			
		||||
    weight?: string;
 | 
			
		||||
}
 | 
			
		||||
interface Path {
 | 
			
		||||
    id: string; // pool address if direct path, contactenation of pool addresses if multihop
 | 
			
		||||
    swaps: Swap[];
 | 
			
		||||
    poolPairData?: PoolPairData[];
 | 
			
		||||
    limitAmount?: BigNumber;
 | 
			
		||||
    filterEffectivePrice?: BigNumber; // TODO: This is just used for filtering, maybe there is a better way to filter?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface Swap {
 | 
			
		||||
    pool: string;
 | 
			
		||||
    tokenIn: string;
 | 
			
		||||
    tokenOut: string;
 | 
			
		||||
    swapAmount?: string;
 | 
			
		||||
    limitReturnAmount?: string;
 | 
			
		||||
    maxPrice?: string;
 | 
			
		||||
    tokenInDecimals: number;
 | 
			
		||||
    tokenOutDecimals: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface PoolPairData {
 | 
			
		||||
    id: string;
 | 
			
		||||
    poolType?: string; // Todo: make this a mandatory field?
 | 
			
		||||
    pairType?: string; // Todo: make this a mandatory field?
 | 
			
		||||
    tokenIn: string;
 | 
			
		||||
    tokenOut: string;
 | 
			
		||||
    balanceIn?: BigNumber;
 | 
			
		||||
    balanceOut?: BigNumber;
 | 
			
		||||
    decimalsIn: number;
 | 
			
		||||
    decimalsOut: number;
 | 
			
		||||
    swapFee: BigNumber;
 | 
			
		||||
 | 
			
		||||
    // For weighted & element pools
 | 
			
		||||
    weightIn?: BigNumber;
 | 
			
		||||
    weightOut?: BigNumber;
 | 
			
		||||
 | 
			
		||||
    // Only for stable pools
 | 
			
		||||
    allBalances: BigNumber[];
 | 
			
		||||
    invariant?: BigNumber;
 | 
			
		||||
    amp?: BigNumber;
 | 
			
		||||
    tokenIndexIn?: number;
 | 
			
		||||
    tokenIndexOut?: number;
 | 
			
		||||
 | 
			
		||||
    // Only for element pools
 | 
			
		||||
    lpShares?: BigNumber;
 | 
			
		||||
    time?: BigNumber;
 | 
			
		||||
    principalToken?: string;
 | 
			
		||||
    baseToken?: string;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,107 +0,0 @@
 | 
			
		||||
import { getPoolsWithTokens, parsePoolData } from '@balancer-labs/sor';
 | 
			
		||||
import { Pool } from '@balancer-labs/sor/dist/types';
 | 
			
		||||
import { gql, request } from 'graphql-request';
 | 
			
		||||
 | 
			
		||||
import { BALANCER_MAX_POOLS_FETCHED, BALANCER_SUBGRAPH_URL, BALANCER_TOP_POOLS_FETCHED } from '../constants';
 | 
			
		||||
 | 
			
		||||
import { CacheValue, PoolsCache } from './pools_cache';
 | 
			
		||||
 | 
			
		||||
// tslint:disable:custom-no-magic-numbers
 | 
			
		||||
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
 | 
			
		||||
// tslint:enable:custom-no-magic-numbers
 | 
			
		||||
 | 
			
		||||
interface BalancerPoolResponse {
 | 
			
		||||
    id: string;
 | 
			
		||||
    swapFee: string;
 | 
			
		||||
    tokens: Array<{ address: string; decimals: number; balance: string }>;
 | 
			
		||||
    tokensList: string[];
 | 
			
		||||
    totalWeight: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class BalancerPoolsCache extends PoolsCache {
 | 
			
		||||
    constructor(
 | 
			
		||||
        private readonly _subgraphUrl: string = BALANCER_SUBGRAPH_URL,
 | 
			
		||||
        cache: { [key: string]: CacheValue } = {},
 | 
			
		||||
        private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
 | 
			
		||||
        private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED,
 | 
			
		||||
    ) {
 | 
			
		||||
        super(cache);
 | 
			
		||||
        void this._loadTopPoolsAsync();
 | 
			
		||||
        // Reload the top pools every 12 hours
 | 
			
		||||
        setInterval(async () => void this._loadTopPoolsAsync(), ONE_DAY_MS / 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
 | 
			
		||||
        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 [];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected async _loadTopPoolsAsync(): Promise<void> {
 | 
			
		||||
        const fromToPools: {
 | 
			
		||||
            [from: string]: { [to: string]: Pool[] };
 | 
			
		||||
        } = {};
 | 
			
		||||
 | 
			
		||||
        const pools = await this._fetchTopPoolsAsync();
 | 
			
		||||
        for (const pool of pools) {
 | 
			
		||||
            const { tokensList } = pool;
 | 
			
		||||
            for (const from of tokensList) {
 | 
			
		||||
                for (const to of tokensList.filter(t => t.toLowerCase() !== from.toLowerCase())) {
 | 
			
		||||
                    fromToPools[from] = fromToPools[from] || {};
 | 
			
		||||
                    fromToPools[from][to] = fromToPools[from][to] || [];
 | 
			
		||||
 | 
			
		||||
                    try {
 | 
			
		||||
                        // The list of pools must be relevant to `from` and `to`  for `parsePoolData`
 | 
			
		||||
                        const poolData = parsePoolData([pool], from, to);
 | 
			
		||||
                        fromToPools[from][to].push(poolData[0]);
 | 
			
		||||
                        // Cache this as we progress through
 | 
			
		||||
                        const expiresAt = Date.now() + this._cacheTimeMs;
 | 
			
		||||
                        this._cachePoolsForPair(from, to, fromToPools[from][to], expiresAt);
 | 
			
		||||
                    } catch {
 | 
			
		||||
                        // soldier on
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected async _fetchTopPoolsAsync(): Promise<BalancerPoolResponse[]> {
 | 
			
		||||
        const query = gql`
 | 
			
		||||
            query fetchTopPools($topPoolsFetched: Int!) {
 | 
			
		||||
                pools(
 | 
			
		||||
                    first: $topPoolsFetched
 | 
			
		||||
                    where: { publicSwap: true, liquidity_gt: 0 }
 | 
			
		||||
                    orderBy: swapsCount
 | 
			
		||||
                    orderDirection: desc
 | 
			
		||||
                ) {
 | 
			
		||||
                    id
 | 
			
		||||
                    publicSwap
 | 
			
		||||
                    swapFee
 | 
			
		||||
                    totalWeight
 | 
			
		||||
                    tokensList
 | 
			
		||||
                    tokens {
 | 
			
		||||
                        id
 | 
			
		||||
                        address
 | 
			
		||||
                        balance
 | 
			
		||||
                        decimals
 | 
			
		||||
                        symbol
 | 
			
		||||
                        denormWeight
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        `;
 | 
			
		||||
        try {
 | 
			
		||||
            const { pools } = await request(this._subgraphUrl, query, { topPoolsFetched: this._topPoolsFetched });
 | 
			
		||||
            return pools;
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,178 +0,0 @@
 | 
			
		||||
import { ChainId } from '@0x/contract-addresses';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
// import { parsePoolData } from '@balancer-labs'; // TODO - upgrade to v2
 | 
			
		||||
import { Pool } from '@balancer-labs/sor/dist/types';
 | 
			
		||||
import { gql, request } from 'graphql-request';
 | 
			
		||||
 | 
			
		||||
import { DEFAULT_WARNING_LOGGER } from '../../../constants';
 | 
			
		||||
import { LogFunction } from '../../../types';
 | 
			
		||||
import {
 | 
			
		||||
    BALANCER_MAX_POOLS_FETCHED,
 | 
			
		||||
    BALANCER_TOP_POOLS_FETCHED,
 | 
			
		||||
    BALANCER_V2_SUBGRAPH_URL_BY_CHAIN,
 | 
			
		||||
} from '../constants';
 | 
			
		||||
 | 
			
		||||
import { parsePoolData } from './balancer_sor_v2';
 | 
			
		||||
import { CacheValue, PoolsCache } from './pools_cache';
 | 
			
		||||
 | 
			
		||||
// tslint:disable-next-line:custom-no-magic-numbers
 | 
			
		||||
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
 | 
			
		||||
 | 
			
		||||
interface BalancerPoolResponse {
 | 
			
		||||
    id: string;
 | 
			
		||||
    swapFee: string;
 | 
			
		||||
    tokens: Array<{ address: string; decimals: number; balance: string; weight: string; symbol: string }>;
 | 
			
		||||
    tokensList: string[];
 | 
			
		||||
    totalWeight: string;
 | 
			
		||||
    totalShares: string;
 | 
			
		||||
    amp: string | null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class BalancerV2PoolsCache extends PoolsCache {
 | 
			
		||||
    private static _parseSubgraphPoolData(pool: any, takerToken: string, makerToken: string): Pool {
 | 
			
		||||
        const tToken = pool.tokens.find((t: any) => t.address === takerToken);
 | 
			
		||||
        const mToken = pool.tokens.find((t: any) => t.address === makerToken);
 | 
			
		||||
        const swap = pool.swaps && pool.swaps[0];
 | 
			
		||||
        const tokenAmountOut = swap ? swap.tokenAmountOut : undefined;
 | 
			
		||||
        const tokenAmountIn = swap ? swap.tokenAmountIn : undefined;
 | 
			
		||||
        const spotPrice =
 | 
			
		||||
            tokenAmountOut && tokenAmountIn ? new BigNumber(tokenAmountOut).div(tokenAmountIn) : undefined; // TODO: xianny check
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            id: pool.id,
 | 
			
		||||
            balanceIn: new BigNumber(tToken.balance),
 | 
			
		||||
            balanceOut: new BigNumber(mToken.balance),
 | 
			
		||||
            weightIn: new BigNumber(tToken.weight),
 | 
			
		||||
            weightOut: new BigNumber(mToken.weight),
 | 
			
		||||
            swapFee: new BigNumber(pool.swapFee),
 | 
			
		||||
            spotPrice,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        chainId: ChainId,
 | 
			
		||||
        private readonly subgraphUrl: string = BALANCER_V2_SUBGRAPH_URL_BY_CHAIN[chainId],
 | 
			
		||||
        private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
 | 
			
		||||
        private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED,
 | 
			
		||||
        private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,
 | 
			
		||||
        cache: { [key: string]: CacheValue } = {},
 | 
			
		||||
    ) {
 | 
			
		||||
        super(cache);
 | 
			
		||||
        void this._loadTopPoolsAsync();
 | 
			
		||||
        // Reload the top pools every 12 hours
 | 
			
		||||
        setInterval(async () => void this._loadTopPoolsAsync(), ONE_DAY_MS / 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
 | 
			
		||||
    //     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 [];
 | 
			
		||||
    //     }
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    protected async _fetchTopPoolsAsync(): Promise<BalancerPoolResponse[]> {
 | 
			
		||||
        const query = gql`
 | 
			
		||||
            query fetchTopPools($topPoolsFetched: Int!) {
 | 
			
		||||
                pools(
 | 
			
		||||
                    first: $topPoolsFetched
 | 
			
		||||
                    where: { totalLiquidity_gt: 0 }
 | 
			
		||||
                    orderBy: swapsCount
 | 
			
		||||
                    orderDirection: desc
 | 
			
		||||
                ) {
 | 
			
		||||
                    id
 | 
			
		||||
                    swapFee
 | 
			
		||||
                    totalWeight
 | 
			
		||||
                    tokensList
 | 
			
		||||
                    amp
 | 
			
		||||
                    totalShares
 | 
			
		||||
                    tokens {
 | 
			
		||||
                        id
 | 
			
		||||
                        address
 | 
			
		||||
                        balance
 | 
			
		||||
                        decimals
 | 
			
		||||
                        symbol
 | 
			
		||||
                        weight
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        `;
 | 
			
		||||
 | 
			
		||||
        const { pools } = await request<{ pools: BalancerPoolResponse[] }>(this.subgraphUrl, query, {
 | 
			
		||||
            topPoolsFetched: this._topPoolsFetched,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return pools;
 | 
			
		||||
    }
 | 
			
		||||
    protected async _loadTopPoolsAsync(): Promise<void> {
 | 
			
		||||
        const fromToPools: {
 | 
			
		||||
            [from: string]: { [to: string]: Pool[] };
 | 
			
		||||
        } = {};
 | 
			
		||||
 | 
			
		||||
        const pools = await this._fetchTopPoolsAsync();
 | 
			
		||||
        for (const pool of pools) {
 | 
			
		||||
            const { tokensList } = pool;
 | 
			
		||||
            for (const from of tokensList) {
 | 
			
		||||
                for (const to of tokensList.filter(t => t.toLowerCase() !== from.toLowerCase())) {
 | 
			
		||||
                    fromToPools[from] = fromToPools[from] || {};
 | 
			
		||||
                    fromToPools[from][to] = fromToPools[from][to] || [];
 | 
			
		||||
 | 
			
		||||
                    try {
 | 
			
		||||
                        // The list of pools must be relevant to `from` and `to`  for `parsePoolData`
 | 
			
		||||
                        const [poolData] = parsePoolData({ [pool.id]: pool as any }, from, to);
 | 
			
		||||
                        fromToPools[from][to].push(
 | 
			
		||||
                            BalancerV2PoolsCache._parseSubgraphPoolData(poolData[pool.id], from, to),
 | 
			
		||||
                        );
 | 
			
		||||
                        // Cache this as we progress through
 | 
			
		||||
                        const expiresAt = Date.now() + this._cacheTimeMs;
 | 
			
		||||
                        this._cachePoolsForPair(from, to, fromToPools[from][to], expiresAt);
 | 
			
		||||
                    } catch (err) {
 | 
			
		||||
                        this._warningLogger(err, `Failed to load Balancer V2 top pools`);
 | 
			
		||||
                        // soldier on
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
 | 
			
		||||
        const query = gql`
 | 
			
		||||
        query getPools {
 | 
			
		||||
            pools(
 | 
			
		||||
              first: ${this.maxPoolsFetched},
 | 
			
		||||
              where: {
 | 
			
		||||
                tokensList_contains: ["${takerToken}", "${makerToken}"]
 | 
			
		||||
              }
 | 
			
		||||
            ) {
 | 
			
		||||
                id
 | 
			
		||||
                tokens {
 | 
			
		||||
                    address
 | 
			
		||||
                    balance
 | 
			
		||||
                    weight
 | 
			
		||||
                }
 | 
			
		||||
              swapFee
 | 
			
		||||
              swaps(
 | 
			
		||||
                orderBy: timestamp, orderDirection: desc, first: 1,
 | 
			
		||||
                  where:{
 | 
			
		||||
                  tokenIn: "${takerToken}",
 | 
			
		||||
                  tokenOut: "${makerToken}"
 | 
			
		||||
                }
 | 
			
		||||
              ) {
 | 
			
		||||
                tokenAmountIn
 | 
			
		||||
                tokenAmountOut
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          `;
 | 
			
		||||
        try {
 | 
			
		||||
            const { pools } = await request(this.subgraphUrl, query);
 | 
			
		||||
            return pools.map((pool: any) => BalancerV2PoolsCache._parseSubgraphPoolData(pool, takerToken, makerToken));
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
import { Pool } from '@balancer-labs/sor/dist/types';
 | 
			
		||||
import { getPoolsWithTokens, parsePoolData } from 'cream-sor';
 | 
			
		||||
 | 
			
		||||
import { BALANCER_MAX_POOLS_FETCHED } from '../constants';
 | 
			
		||||
 | 
			
		||||
import { CacheValue, PoolsCache } from './pools_cache';
 | 
			
		||||
 | 
			
		||||
export class CreamPoolsCache extends PoolsCache {
 | 
			
		||||
    constructor(
 | 
			
		||||
        _cache: { [key: string]: CacheValue } = {},
 | 
			
		||||
        private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
 | 
			
		||||
    ) {
 | 
			
		||||
        super(_cache);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
 | 
			
		||||
        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.slice(0, this.maxPoolsFetched);
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +0,0 @@
 | 
			
		||||
export { BalancerPoolsCache } from './balancer_utils';
 | 
			
		||||
export { BalancerV2PoolsCache } from './balancer_v2_utils';
 | 
			
		||||
export { CreamPoolsCache } from './cream_utils';
 | 
			
		||||
export { PoolsCache } from './pools_cache';
 | 
			
		||||
@@ -1,78 +0,0 @@
 | 
			
		||||
import { Pool } from '@balancer-labs/sor/dist/types';
 | 
			
		||||
 | 
			
		||||
import { ONE_HOUR_IN_SECONDS, ONE_SECOND_MS } from '../constants';
 | 
			
		||||
export { Pool };
 | 
			
		||||
export interface CacheValue {
 | 
			
		||||
    expiresAt: number;
 | 
			
		||||
    pools: Pool[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tslint:disable:custom-no-magic-numbers
 | 
			
		||||
// Cache results for 30mins
 | 
			
		||||
const DEFAULT_CACHE_TIME_MS = (ONE_HOUR_IN_SECONDS / 2) * ONE_SECOND_MS;
 | 
			
		||||
const DEFAULT_TIMEOUT_MS = 1000;
 | 
			
		||||
// tslint:enable:custom-no-magic-numbers
 | 
			
		||||
 | 
			
		||||
export abstract class PoolsCache {
 | 
			
		||||
    protected static _isExpired(value: CacheValue): boolean {
 | 
			
		||||
        return Date.now() >= value.expiresAt;
 | 
			
		||||
    }
 | 
			
		||||
    constructor(
 | 
			
		||||
        protected readonly _cache: { [key: string]: CacheValue },
 | 
			
		||||
        protected readonly _cacheTimeMs: number = DEFAULT_CACHE_TIME_MS,
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    public async getFreshPoolsForPairAsync(
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        timeoutMs: number = DEFAULT_TIMEOUT_MS,
 | 
			
		||||
    ): Promise<Pool[]> {
 | 
			
		||||
        const timeout = new Promise<Pool[]>(resolve => setTimeout(resolve, timeoutMs, []));
 | 
			
		||||
        return Promise.race([this._getAndSaveFreshPoolsForPairAsync(takerToken, makerToken), timeout]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public getCachedPoolAddressesForPair(
 | 
			
		||||
        takerToken: string,
 | 
			
		||||
        makerToken: string,
 | 
			
		||||
        ignoreExpired: boolean = true,
 | 
			
		||||
    ): string[] | undefined {
 | 
			
		||||
        const key = JSON.stringify([takerToken, makerToken]);
 | 
			
		||||
        const value = this._cache[key];
 | 
			
		||||
        if (ignoreExpired) {
 | 
			
		||||
            return value === undefined ? [] : value.pools.map(pool => pool.id);
 | 
			
		||||
        }
 | 
			
		||||
        if (!value) {
 | 
			
		||||
            return undefined;
 | 
			
		||||
        }
 | 
			
		||||
        if (PoolsCache._isExpired(value)) {
 | 
			
		||||
            return undefined;
 | 
			
		||||
        }
 | 
			
		||||
        return (value || []).pools.map(pool => pool.id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public isFresh(takerToken: string, makerToken: string): boolean {
 | 
			
		||||
        const cached = this.getCachedPoolAddressesForPair(takerToken, makerToken, false);
 | 
			
		||||
        return cached !== undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected async _getAndSaveFreshPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
 | 
			
		||||
        const key = JSON.stringify([takerToken, makerToken]);
 | 
			
		||||
        const value = this._cache[key];
 | 
			
		||||
        if (value === undefined || value.expiresAt >= Date.now()) {
 | 
			
		||||
            const pools = await this._fetchPoolsForPairAsync(takerToken, makerToken);
 | 
			
		||||
            const expiresAt = Date.now() + this._cacheTimeMs;
 | 
			
		||||
            this._cachePoolsForPair(takerToken, makerToken, pools, expiresAt);
 | 
			
		||||
        }
 | 
			
		||||
        return this._cache[key].pools;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected _cachePoolsForPair(takerToken: string, makerToken: string, pools: Pool[], expiresAt: number): void {
 | 
			
		||||
        const key = JSON.stringify([takerToken, makerToken]);
 | 
			
		||||
        this._cache[key] = {
 | 
			
		||||
            pools,
 | 
			
		||||
            expiresAt,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]>;
 | 
			
		||||
}
 | 
			
		||||
@@ -2,38 +2,10 @@ import { BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { MarketOperation } from '../../types';
 | 
			
		||||
 | 
			
		||||
import { SOURCE_FLAGS, ZERO_AMOUNT } from './constants';
 | 
			
		||||
import { DexSample, ERC20BridgeSource, ExchangeProxyOverhead, FeeSchedule, MultiHopFillData } from './types';
 | 
			
		||||
import { ZERO_AMOUNT } from './constants';
 | 
			
		||||
 | 
			
		||||
// tslint:disable:no-bitwise
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the fee-adjusted rate of a two-hop quote. Returns zero if the
 | 
			
		||||
 * quote falls short of the target input.
 | 
			
		||||
 */
 | 
			
		||||
export function getTwoHopAdjustedRate(
 | 
			
		||||
    side: MarketOperation,
 | 
			
		||||
    twoHopQuote: DexSample<MultiHopFillData>,
 | 
			
		||||
    targetInput: BigNumber,
 | 
			
		||||
    outputAmountPerEth: BigNumber,
 | 
			
		||||
    fees: FeeSchedule = {},
 | 
			
		||||
    exchangeProxyOverhead: ExchangeProxyOverhead = () => ZERO_AMOUNT,
 | 
			
		||||
): BigNumber {
 | 
			
		||||
    const { output, input, fillData } = twoHopQuote;
 | 
			
		||||
    if (input.isLessThan(targetInput) || output.isZero()) {
 | 
			
		||||
        return ZERO_AMOUNT;
 | 
			
		||||
    }
 | 
			
		||||
    const penalty = outputAmountPerEth.times(
 | 
			
		||||
        exchangeProxyOverhead(
 | 
			
		||||
            SOURCE_FLAGS.MultiHop |
 | 
			
		||||
                SOURCE_FLAGS[fillData.firstHopSource.source] |
 | 
			
		||||
                SOURCE_FLAGS[fillData.secondHopSource.source],
 | 
			
		||||
        ).plus(fees[ERC20BridgeSource.MultiHop]!(fillData)),
 | 
			
		||||
    );
 | 
			
		||||
    const adjustedOutput = side === MarketOperation.Sell ? output.minus(penalty) : output.plus(penalty);
 | 
			
		||||
    return side === MarketOperation.Sell ? adjustedOutput.div(input) : input.div(adjustedOutput);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Computes the "complete" rate given the input/output of a path.
 | 
			
		||||
 * This value penalizes the path if it falls short of the target input.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,167 +1,87 @@
 | 
			
		||||
import { ChainId } from '@0x/contract-addresses';
 | 
			
		||||
import { BigNumber, NULL_BYTES } from '@0x/utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { SamplerOverrides } from '../../types';
 | 
			
		||||
import { ERC20BridgeSamplerContract } from '../../wrappers';
 | 
			
		||||
import { Address } from '../../types';
 | 
			
		||||
 | 
			
		||||
import { BancorService } from './bancor_service';
 | 
			
		||||
import { PoolsCache } from './pools_cache';
 | 
			
		||||
import { SamplerOperations } from './sampler_operations';
 | 
			
		||||
import { BatchedOperation, ERC20BridgeSource, LiquidityProviderRegistry, TokenAdjacencyGraph } from './types';
 | 
			
		||||
import { DexSample, ERC20BridgeSource, TokenAdjacencyGraph } from './types';
 | 
			
		||||
import { SamplerServiceRpcClient } from './sampler_service_rpc_client';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Generate sample amounts up to `maxFillAmount`.
 | 
			
		||||
 */
 | 
			
		||||
export function getSampleAmounts(maxFillAmount: BigNumber, numSamples: number, expBase: number = 1): BigNumber[] {
 | 
			
		||||
    const distribution = [...Array<BigNumber>(numSamples)].map((_v, i) => new BigNumber(expBase).pow(i));
 | 
			
		||||
    const stepSizes = distribution.map(d => d.div(BigNumber.sum(...distribution)));
 | 
			
		||||
    const amounts = stepSizes.map((_s, i) => {
 | 
			
		||||
        if (i === numSamples - 1) {
 | 
			
		||||
            return maxFillAmount;
 | 
			
		||||
        }
 | 
			
		||||
        return maxFillAmount
 | 
			
		||||
            .times(BigNumber.sum(...[0, ...stepSizes.slice(0, i + 1)]))
 | 
			
		||||
            .integerValue(BigNumber.ROUND_UP);
 | 
			
		||||
    });
 | 
			
		||||
    return amounts;
 | 
			
		||||
interface TokenInfo {
 | 
			
		||||
    decimals: number;
 | 
			
		||||
    address: Address;
 | 
			
		||||
    gasCost: number;
 | 
			
		||||
    symbol: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type BatchedOperationResult<T> = T extends BatchedOperation<infer TResult> ? TResult : never;
 | 
			
		||||
export interface Sampler {
 | 
			
		||||
    chainId: ChainId;
 | 
			
		||||
    getTokenInfosAsync(tokens: Address[]): Promise<TokenInfo[]>;
 | 
			
		||||
    getPricesAsync(paths: Address[][], sources: ERC20BridgeSource[]): Promise<BigNumber[]>;
 | 
			
		||||
    getSellLiquidityAsync(path: Address[], takerAmount: BigNumber, sources: ERC20BridgeSource[]): Promise<DexSample[][]>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Encapsulates interactions with the `ERC20BridgeSampler` contract.
 | 
			
		||||
 */
 | 
			
		||||
export class DexOrderSampler extends SamplerOperations {
 | 
			
		||||
    constructor(
 | 
			
		||||
        public readonly chainId: ChainId,
 | 
			
		||||
        _samplerContract: ERC20BridgeSamplerContract,
 | 
			
		||||
        private readonly _samplerOverrides?: SamplerOverrides,
 | 
			
		||||
        poolsCaches?: { [key in ERC20BridgeSource]: PoolsCache },
 | 
			
		||||
        tokenAdjacencyGraph?: TokenAdjacencyGraph,
 | 
			
		||||
        liquidityProviderRegistry?: LiquidityProviderRegistry,
 | 
			
		||||
        bancorServiceFn: () => Promise<BancorService | undefined> = async () => undefined,
 | 
			
		||||
    ) {
 | 
			
		||||
        super(chainId, _samplerContract, poolsCaches, tokenAdjacencyGraph, liquidityProviderRegistry, bancorServiceFn);
 | 
			
		||||
export class SamplerClient implements Sampler {
 | 
			
		||||
    static createFromChainIdAndEndpoint(chainId: ChainId, endpoint: string): SamplerClient {
 | 
			
		||||
        return new SamplerClient(chainId, new SamplerServiceRpcClient(endpoint));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Type overloads for `executeAsync()`. Could skip this if we would upgrade TS. */
 | 
			
		||||
 | 
			
		||||
    // prettier-ignore
 | 
			
		||||
    public async executeAsync<
 | 
			
		||||
        T1
 | 
			
		||||
    >(...ops: [T1]): Promise<[
 | 
			
		||||
        BatchedOperationResult<T1>
 | 
			
		||||
    ]>;
 | 
			
		||||
 | 
			
		||||
    // prettier-ignore
 | 
			
		||||
    public async executeAsync<
 | 
			
		||||
        T1, T2
 | 
			
		||||
    >(...ops: [T1, T2]): Promise<[
 | 
			
		||||
        BatchedOperationResult<T1>,
 | 
			
		||||
        BatchedOperationResult<T2>
 | 
			
		||||
    ]>;
 | 
			
		||||
 | 
			
		||||
    // prettier-ignore
 | 
			
		||||
    public async executeAsync<
 | 
			
		||||
        T1, T2, T3
 | 
			
		||||
    >(...ops: [T1, T2, T3]): Promise<[
 | 
			
		||||
        BatchedOperationResult<T1>,
 | 
			
		||||
        BatchedOperationResult<T2>,
 | 
			
		||||
        BatchedOperationResult<T3>
 | 
			
		||||
    ]>;
 | 
			
		||||
 | 
			
		||||
    // prettier-ignore
 | 
			
		||||
    public async executeAsync<
 | 
			
		||||
        T1, T2, T3, T4
 | 
			
		||||
    >(...ops: [T1, T2, T3, T4]): Promise<[
 | 
			
		||||
        BatchedOperationResult<T1>,
 | 
			
		||||
        BatchedOperationResult<T2>,
 | 
			
		||||
        BatchedOperationResult<T3>,
 | 
			
		||||
        BatchedOperationResult<T4>
 | 
			
		||||
    ]>;
 | 
			
		||||
 | 
			
		||||
    // prettier-ignore
 | 
			
		||||
    public async executeAsync<
 | 
			
		||||
        T1, T2, T3, T4, T5
 | 
			
		||||
    >(...ops: [T1, T2, T3, T4, T5]): Promise<[
 | 
			
		||||
        BatchedOperationResult<T1>,
 | 
			
		||||
        BatchedOperationResult<T2>,
 | 
			
		||||
        BatchedOperationResult<T3>,
 | 
			
		||||
        BatchedOperationResult<T4>,
 | 
			
		||||
        BatchedOperationResult<T5>
 | 
			
		||||
    ]>;
 | 
			
		||||
 | 
			
		||||
    // prettier-ignore
 | 
			
		||||
    public async executeAsync<
 | 
			
		||||
        T1, T2, T3, T4, T5, T6
 | 
			
		||||
    >(...ops: [T1, T2, T3, T4, T5, T6]): Promise<[
 | 
			
		||||
        BatchedOperationResult<T1>,
 | 
			
		||||
        BatchedOperationResult<T2>,
 | 
			
		||||
        BatchedOperationResult<T3>,
 | 
			
		||||
        BatchedOperationResult<T4>,
 | 
			
		||||
        BatchedOperationResult<T5>,
 | 
			
		||||
        BatchedOperationResult<T6>
 | 
			
		||||
    ]>;
 | 
			
		||||
 | 
			
		||||
    // prettier-ignore
 | 
			
		||||
    public async executeAsync<
 | 
			
		||||
        T1, T2, T3, T4, T5, T6, T7
 | 
			
		||||
    >(...ops: [T1, T2, T3, T4, T5, T6, T7]): Promise<[
 | 
			
		||||
        BatchedOperationResult<T1>,
 | 
			
		||||
        BatchedOperationResult<T2>,
 | 
			
		||||
        BatchedOperationResult<T3>,
 | 
			
		||||
        BatchedOperationResult<T4>,
 | 
			
		||||
        BatchedOperationResult<T5>,
 | 
			
		||||
        BatchedOperationResult<T6>,
 | 
			
		||||
        BatchedOperationResult<T7>
 | 
			
		||||
    ]>;
 | 
			
		||||
 | 
			
		||||
    // prettier-ignore
 | 
			
		||||
    public async executeAsync<
 | 
			
		||||
        T1, T2, T3, T4, T5, T6, T7, T8
 | 
			
		||||
    >(...ops: [T1, T2, T3, T4, T5, T6, T7, T8]): Promise<[
 | 
			
		||||
        BatchedOperationResult<T1>,
 | 
			
		||||
        BatchedOperationResult<T2>,
 | 
			
		||||
        BatchedOperationResult<T3>,
 | 
			
		||||
        BatchedOperationResult<T4>,
 | 
			
		||||
        BatchedOperationResult<T5>,
 | 
			
		||||
        BatchedOperationResult<T6>,
 | 
			
		||||
        BatchedOperationResult<T7>,
 | 
			
		||||
        BatchedOperationResult<T8>
 | 
			
		||||
    ]>;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Run a series of operations from `DexOrderSampler.ops` in a single transaction.
 | 
			
		||||
     */
 | 
			
		||||
    public async executeAsync(...ops: any[]): Promise<any[]> {
 | 
			
		||||
        return this.executeBatchAsync(ops);
 | 
			
		||||
    static async createFromEndpointAsync(endpoint: string): Promise<SamplerClient> {
 | 
			
		||||
        const service = new SamplerServiceRpcClient(endpoint);
 | 
			
		||||
        const chainId = await service.getChainIdAsync();
 | 
			
		||||
        return new SamplerClient(
 | 
			
		||||
            chainId,
 | 
			
		||||
            service,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Run a series of operations from `DexOrderSampler.ops` in a single transaction.
 | 
			
		||||
     * Takes an arbitrary length array, but is not typesafe.
 | 
			
		||||
     */
 | 
			
		||||
    public async executeBatchAsync<T extends Array<BatchedOperation<any>>>(ops: T): Promise<any[]> {
 | 
			
		||||
        const callDatas = ops.map(o => o.encodeCall());
 | 
			
		||||
        const { overrides, block } = this._samplerOverrides
 | 
			
		||||
            ? this._samplerOverrides
 | 
			
		||||
            : { overrides: undefined, block: undefined };
 | 
			
		||||
    private constructor(
 | 
			
		||||
        private readonly _chainId: number,
 | 
			
		||||
        private readonly _service: SamplerServiceRpcClient,
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
        // All operations are NOOPs
 | 
			
		||||
        if (callDatas.every(cd => cd === NULL_BYTES)) {
 | 
			
		||||
            return callDatas.map((_callData, i) => ops[i].handleCallResults(NULL_BYTES));
 | 
			
		||||
        }
 | 
			
		||||
        // Execute all non-empty calldatas.
 | 
			
		||||
        const rawCallResults = await this._samplerContract
 | 
			
		||||
            .batchCall(callDatas.filter(cd => cd !== NULL_BYTES))
 | 
			
		||||
            .callAsync({ overrides }, block);
 | 
			
		||||
        // Return the parsed results.
 | 
			
		||||
        let rawCallResultsIdx = 0;
 | 
			
		||||
        return callDatas.map((callData, i) => {
 | 
			
		||||
            // tslint:disable-next-line:boolean-naming
 | 
			
		||||
            const { data, success } =
 | 
			
		||||
                callData !== NULL_BYTES ? rawCallResults[rawCallResultsIdx++] : { success: true, data: NULL_BYTES };
 | 
			
		||||
            return success ? ops[i].handleCallResults(data) : ops[i].handleRevert(data);
 | 
			
		||||
        });
 | 
			
		||||
    public get chainId(): ChainId {
 | 
			
		||||
        return this._chainId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async getPricesAsync(
 | 
			
		||||
        paths: Address[][],
 | 
			
		||||
        sources: ERC20BridgeSource[],
 | 
			
		||||
    ): Promise<BigNumber[]> {
 | 
			
		||||
        return this._service.getPricesAsync(paths.map(p => ({
 | 
			
		||||
            tokenPath: p,
 | 
			
		||||
            demand: true,
 | 
			
		||||
            sources,
 | 
			
		||||
        })));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async getTokenInfosAsync(tokens: Address[]): Promise<TokenInfo[]> {
 | 
			
		||||
        return this._service.getTokensAsync(tokens);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async getSellLiquidityAsync(
 | 
			
		||||
        path: Address[],
 | 
			
		||||
        takerAmount: BigNumber,
 | 
			
		||||
        sources: ERC20BridgeSource[],
 | 
			
		||||
    ): Promise<DexSample[][]> {
 | 
			
		||||
        const liquidity = await this._service.getSellLiquidityAsync(
 | 
			
		||||
            sources.map(s => ({
 | 
			
		||||
                tokenPath: path,
 | 
			
		||||
                inputAmount: takerAmount,
 | 
			
		||||
                source: s,
 | 
			
		||||
                demand: true,
 | 
			
		||||
            })),
 | 
			
		||||
        );
 | 
			
		||||
        return liquidity.map(
 | 
			
		||||
            liq => liq.liquidityCurves.map(
 | 
			
		||||
                pts =>
 | 
			
		||||
                    pts.map(pt => ({
 | 
			
		||||
                        input: pt.sellAmount,
 | 
			
		||||
                        output: pt.buyAmount,
 | 
			
		||||
                        encodedFillData: pt.encodedFillData,
 | 
			
		||||
                        metadata: pt.metadata,
 | 
			
		||||
                        gasCost: pt.gasCost,
 | 
			
		||||
                        source: liq.source,
 | 
			
		||||
                    }) as DexSample),
 | 
			
		||||
        )).flat(1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,62 +0,0 @@
 | 
			
		||||
import { ContractFunctionObj } from '@0x/base-contract';
 | 
			
		||||
import { BigNumber, decodeBytesAsRevertError, logUtils } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { ERC20BridgeSamplerContract } from '../../wrappers';
 | 
			
		||||
 | 
			
		||||
import { ERC20BridgeSource, FillData, SourceQuoteOperation } from './types';
 | 
			
		||||
 | 
			
		||||
export type Parameters<T> = T extends (...args: infer TArgs) => any ? TArgs : never;
 | 
			
		||||
 | 
			
		||||
export interface SamplerContractCall<
 | 
			
		||||
    TFunc extends (...args: any[]) => ContractFunctionObj<any>,
 | 
			
		||||
    TFillData extends FillData = FillData
 | 
			
		||||
> {
 | 
			
		||||
    contract: ERC20BridgeSamplerContract;
 | 
			
		||||
    function: TFunc;
 | 
			
		||||
    params: Parameters<TFunc>;
 | 
			
		||||
    callback?: (callResults: string, fillData: TFillData) => BigNumber[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class SamplerContractOperation<
 | 
			
		||||
    TFunc extends (...args: any[]) => ContractFunctionObj<any>,
 | 
			
		||||
    TFillData extends FillData = FillData
 | 
			
		||||
> implements SourceQuoteOperation<TFillData> {
 | 
			
		||||
    public readonly source: ERC20BridgeSource;
 | 
			
		||||
    public fillData: TFillData;
 | 
			
		||||
    private readonly _samplerContract: ERC20BridgeSamplerContract;
 | 
			
		||||
    private readonly _samplerFunction: TFunc;
 | 
			
		||||
    private readonly _params: Parameters<TFunc>;
 | 
			
		||||
    private readonly _callback?: (callResults: string, fillData: TFillData) => BigNumber[];
 | 
			
		||||
 | 
			
		||||
    constructor(opts: { source: ERC20BridgeSource; fillData?: TFillData } & SamplerContractCall<TFunc, TFillData>) {
 | 
			
		||||
        this.source = opts.source;
 | 
			
		||||
        this.fillData = opts.fillData || ({} as TFillData); // tslint:disable-line:no-object-literal-type-assertion
 | 
			
		||||
        this._samplerContract = opts.contract;
 | 
			
		||||
        this._samplerFunction = opts.function;
 | 
			
		||||
        this._params = opts.params;
 | 
			
		||||
        this._callback = opts.callback;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public encodeCall(): string {
 | 
			
		||||
        return this._samplerFunction
 | 
			
		||||
            .bind(this._samplerContract)(...this._params)
 | 
			
		||||
            .getABIEncodedTransactionData();
 | 
			
		||||
    }
 | 
			
		||||
    public handleCallResults(callResults: string): BigNumber[] {
 | 
			
		||||
        if (this._callback !== undefined) {
 | 
			
		||||
            return this._callback(callResults, this.fillData);
 | 
			
		||||
        } else {
 | 
			
		||||
            return this._samplerContract.getABIDecodedReturnData<BigNumber[]>(this._samplerFunction.name, callResults);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    public handleRevert(callResults: string): BigNumber[] {
 | 
			
		||||
        let msg = callResults;
 | 
			
		||||
        try {
 | 
			
		||||
            msg = decodeBytesAsRevertError(callResults).toString();
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            // do nothing
 | 
			
		||||
        }
 | 
			
		||||
        logUtils.warn(`SamplerContractOperation: ${this.source}.${this._samplerFunction.name} reverted ${msg}`);
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,168 @@
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { Client as OpenRpcClient, HTTPTransport, RequestManager } from '@open-rpc/client-js';
 | 
			
		||||
 | 
			
		||||
import { Address, Bytes } from '../../types';
 | 
			
		||||
 | 
			
		||||
type DecimalString = string;
 | 
			
		||||
 | 
			
		||||
export interface LiquidityCurvePoint {
 | 
			
		||||
    sellAmount: BigNumber;
 | 
			
		||||
    buyAmount: BigNumber;
 | 
			
		||||
    encodedFillData: Bytes;
 | 
			
		||||
    metadata: object;
 | 
			
		||||
    gasCost: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface RpcLiquidityCurvePoint {
 | 
			
		||||
    sellAmount: DecimalString;
 | 
			
		||||
    buyAmount: DecimalString;
 | 
			
		||||
    encodedFillData: Bytes;
 | 
			
		||||
    jsonMetadata: string;
 | 
			
		||||
    gasCost: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface LiquidityRequest {
 | 
			
		||||
    tokenPath: Address[];
 | 
			
		||||
    inputAmount: BigNumber;
 | 
			
		||||
    source: string;
 | 
			
		||||
    demand?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RpcLiquidityRequest = Omit<LiquidityRequest, 'inputAmount'> & {
 | 
			
		||||
    inputAmount: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface PriceRequest {
 | 
			
		||||
    tokenPath: Address[];
 | 
			
		||||
    sources?: string[];
 | 
			
		||||
    demand?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RpcPriceRequest = PriceRequest;
 | 
			
		||||
 | 
			
		||||
export interface LiquidityResponse {
 | 
			
		||||
    source: string;
 | 
			
		||||
    liquidityCurves: LiquidityCurvePoint[][];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RpcLiquidityResponse = & Omit<LiquidityResponse, 'liquidityCurves'> & {
 | 
			
		||||
    source: string;
 | 
			
		||||
    liquidityCurves: RpcLiquidityCurvePoint[][];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface TokenResponse {
 | 
			
		||||
    address: Address;
 | 
			
		||||
    symbol: string;
 | 
			
		||||
    decimals: number;
 | 
			
		||||
    gasCost: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RpcTokenResponse = TokenResponse;
 | 
			
		||||
 | 
			
		||||
export class SamplerServiceRpcClient {
 | 
			
		||||
    private _rpcClient: OpenRpcClient;
 | 
			
		||||
 | 
			
		||||
    public constructor(url: string) {
 | 
			
		||||
        const transport = new HTTPTransport(url);
 | 
			
		||||
        // HACK(dorothy-zbornak): One of AS/API's deps globally registers a version of
 | 
			
		||||
        // isometric-fetch that doesn't work with open-rpc. It seems to disagree on
 | 
			
		||||
        // the type of 'headers'.
 | 
			
		||||
        (transport as any).headers = {'content-type': 'application/json'};
 | 
			
		||||
        this._rpcClient = new OpenRpcClient(new RequestManager([transport]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async _requestAsync<TResult, TArgs = any>(method: string, params: TArgs[] = []): Promise<TResult> {
 | 
			
		||||
        try {
 | 
			
		||||
            return await this._rpcClient.request({ method, params }) as Promise<TResult>;
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
            throw new Error(`Error making RPC request "${method}" to sampler service: ${err}`);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async getChainIdAsync(): Promise<number> {
 | 
			
		||||
        return this._requestAsync<number>('get_chain_id');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async getSellLiquidityAsync(reqs: LiquidityRequest[]): Promise<LiquidityResponse[]> {
 | 
			
		||||
        const resp = await this._requestAsync<RpcLiquidityResponse[], RpcLiquidityRequest[]>(
 | 
			
		||||
            'get_sell_liquidity',
 | 
			
		||||
            [
 | 
			
		||||
                reqs.map(r => ({
 | 
			
		||||
                    ...r,
 | 
			
		||||
                    inputAmount: r.inputAmount.toString(10),
 | 
			
		||||
                })),
 | 
			
		||||
            ],
 | 
			
		||||
        );
 | 
			
		||||
        return resp.map(r => ({
 | 
			
		||||
            ...r,
 | 
			
		||||
            liquidityCurves: r.liquidityCurves.map(a => a.map(c => ({
 | 
			
		||||
                ...c,
 | 
			
		||||
                buyAmount: new BigNumber(c.buyAmount),
 | 
			
		||||
                sellAmount: new BigNumber(c.sellAmount),
 | 
			
		||||
                metadata: decodeMetadata(c.jsonMetadata),
 | 
			
		||||
            }))),
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async getBuyLiquidityAsync(reqs: LiquidityRequest[]): Promise<LiquidityResponse[]> {
 | 
			
		||||
        const resp = await this._requestAsync<RpcLiquidityResponse[], RpcLiquidityRequest[]>(
 | 
			
		||||
            'get_buy_liquidity',
 | 
			
		||||
            [
 | 
			
		||||
                reqs.map(r => ({
 | 
			
		||||
                    ...r,
 | 
			
		||||
                    inputAmount: r.inputAmount.toString(10),
 | 
			
		||||
                })),
 | 
			
		||||
            ],
 | 
			
		||||
        );
 | 
			
		||||
        return resp.map(r => ({
 | 
			
		||||
            ...r,
 | 
			
		||||
            liquidityCurves: r.liquidityCurves.map(a => a.map(c => ({
 | 
			
		||||
                ...c,
 | 
			
		||||
                buyAmount: new BigNumber(c.buyAmount),
 | 
			
		||||
                sellAmount: new BigNumber(c.sellAmount),
 | 
			
		||||
                metadata: decodeMetadata(c.jsonMetadata),
 | 
			
		||||
            }))),
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async getPricesAsync(reqs: PriceRequest[]): Promise<BigNumber[]> {
 | 
			
		||||
        const resp = await this._requestAsync<DecimalString[], RpcPriceRequest[]>(
 | 
			
		||||
            'get_prices',
 | 
			
		||||
            [ reqs ],
 | 
			
		||||
        );
 | 
			
		||||
        return resp.map(r => new BigNumber(r));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async getTokensAsync(addresses: Address[]): Promise<TokenResponse[]> {
 | 
			
		||||
        return this._requestAsync<RpcTokenResponse[], Address[]>(
 | 
			
		||||
            'get_tokens',
 | 
			
		||||
            [ addresses ],
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function decodeMetadata(jsonMetadata: string): any {
 | 
			
		||||
    if (!jsonMetadata) {
 | 
			
		||||
        return undefined;
 | 
			
		||||
    }
 | 
			
		||||
    return unmarshallMetadata(JSON.parse(jsonMetadata));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function unmarshallMetadata(v: any): any {
 | 
			
		||||
    switch (typeof(v)) {
 | 
			
		||||
        case 'string':
 | 
			
		||||
            if (/^\d+n$/.test(v)) {
 | 
			
		||||
                return new BigNumber(v.slice(0, -1));
 | 
			
		||||
            }
 | 
			
		||||
            return v;
 | 
			
		||||
        case 'object':
 | 
			
		||||
            if (Array.isArray(v)) {
 | 
			
		||||
                return v.map(v => unmarshallMetadata(v));
 | 
			
		||||
            }
 | 
			
		||||
            return Object.assign(
 | 
			
		||||
                {},
 | 
			
		||||
                ...Object.entries(v).map(([k, v]) => ({ [k]: v})),
 | 
			
		||||
            );
 | 
			
		||||
    }
 | 
			
		||||
    return v;
 | 
			
		||||
}
 | 
			
		||||
@@ -2,12 +2,15 @@ import {
 | 
			
		||||
    FillQuoteTransformerLimitOrderInfo,
 | 
			
		||||
    FillQuoteTransformerOrderType,
 | 
			
		||||
    FillQuoteTransformerRfqOrderInfo,
 | 
			
		||||
    LimitOrderFields,
 | 
			
		||||
    RfqOrderFields,
 | 
			
		||||
    Signature,
 | 
			
		||||
} from '@0x/protocol-utils';
 | 
			
		||||
import { V4RFQIndicativeQuote } from '@0x/quote-server';
 | 
			
		||||
import { MarketOperation } from '@0x/types';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { NativeOrderWithFillableAmounts, RfqFirmQuoteValidator, RfqRequestOpts } from '../../types';
 | 
			
		||||
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';
 | 
			
		||||
 | 
			
		||||
@@ -163,122 +166,57 @@ export interface BalancerV2PoolInfo {
 | 
			
		||||
    vault: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Internal `fillData` field for `Fill` objects.
 | 
			
		||||
export interface FillData {}
 | 
			
		||||
 | 
			
		||||
// `FillData` for native fills. Represents a single native order
 | 
			
		||||
export type NativeRfqOrderFillData = FillQuoteTransformerRfqOrderInfo;
 | 
			
		||||
export type NativeLimitOrderFillData = FillQuoteTransformerLimitOrderInfo;
 | 
			
		||||
export type NativeFillData = NativeRfqOrderFillData | NativeLimitOrderFillData;
 | 
			
		||||
 | 
			
		||||
// Represents an individual DEX sample from the sampler contract
 | 
			
		||||
export interface DexSample<TFillData extends FillData = FillData> {
 | 
			
		||||
export interface DexSample {
 | 
			
		||||
    source: ERC20BridgeSource;
 | 
			
		||||
    fillData: TFillData;
 | 
			
		||||
    encodedFillData: Bytes;
 | 
			
		||||
    metadata?: any;
 | 
			
		||||
    input: BigNumber;
 | 
			
		||||
    output: BigNumber;
 | 
			
		||||
}
 | 
			
		||||
export interface CurveFillData extends FillData {
 | 
			
		||||
    fromTokenIdx: number;
 | 
			
		||||
    toTokenIdx: number;
 | 
			
		||||
    pool: CurveInfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BalancerFillData extends FillData {
 | 
			
		||||
    poolAddress: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BalancerV2FillData extends FillData {
 | 
			
		||||
    vault: string;
 | 
			
		||||
    poolId: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface UniswapV2FillData extends FillData {
 | 
			
		||||
    tokenAddressPath: string[];
 | 
			
		||||
    router: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ShellFillData extends FillData {
 | 
			
		||||
    poolAddress: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface LiquidityProviderFillData extends FillData {
 | 
			
		||||
    poolAddress: string;
 | 
			
		||||
    gasCost: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BancorFillData extends FillData {
 | 
			
		||||
    path: string[];
 | 
			
		||||
    networkAddress: string;
 | 
			
		||||
export interface BridgeFillData {
 | 
			
		||||
    encodedFillData: Bytes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface KyberFillData extends FillData {
 | 
			
		||||
    hint: string;
 | 
			
		||||
    reserveId: string;
 | 
			
		||||
    networkProxy: string;
 | 
			
		||||
export interface UniswapV2FillData extends BridgeFillData {
 | 
			
		||||
    tokenAddressPath: Address[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MooniswapFillData extends FillData {
 | 
			
		||||
    poolAddress: string;
 | 
			
		||||
export interface UniswapV3FillData extends BridgeFillData {
 | 
			
		||||
    encodedPath: Bytes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DODOFillData extends FillData {
 | 
			
		||||
    poolAddress: string;
 | 
			
		||||
    isSellBase: boolean;
 | 
			
		||||
    helperAddress: string;
 | 
			
		||||
export interface LiquidityProviderFillData extends BridgeFillData {
 | 
			
		||||
    poolAddress: Address;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface GenericRouterFillData extends FillData {
 | 
			
		||||
    router: string;
 | 
			
		||||
export interface CurveFillData extends BridgeFillData {
 | 
			
		||||
    poolAddress: Address;
 | 
			
		||||
    exchangeFunctionSelector: Bytes;
 | 
			
		||||
    fromTokenIdx: number;
 | 
			
		||||
    toTokenIdx: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MultiHopFillData extends FillData {
 | 
			
		||||
    firstHopSource: SourceQuoteOperation;
 | 
			
		||||
    secondHopSource: SourceQuoteOperation;
 | 
			
		||||
    intermediateToken: string;
 | 
			
		||||
export interface MooniswapFillData extends BridgeFillData {
 | 
			
		||||
    poolAddress: Address;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MakerPsmExtendedData {
 | 
			
		||||
    isSellOperation: boolean;
 | 
			
		||||
    takerToken: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type MakerPsmFillData = FillData & MakerPsmExtendedData & PsmInfo;
 | 
			
		||||
 | 
			
		||||
export interface HopInfo {
 | 
			
		||||
    sourceIndex: BigNumber;
 | 
			
		||||
    returnData: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface UniswapV3FillData extends FillData {
 | 
			
		||||
    tokenAddressPath: string[];
 | 
			
		||||
    router: string;
 | 
			
		||||
    pathAmounts: Array<{ uniswapPath: string; inputAmount: BigNumber }>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface KyberDmmFillData extends UniswapV2FillData {
 | 
			
		||||
    poolsPath: string[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FinalUniswapV3FillData extends Omit<UniswapV3FillData, 'uniswapPaths'> {
 | 
			
		||||
    // The uniswap-encoded path that can fll the maximum input amount.
 | 
			
		||||
    uniswapPath: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface LidoFillData extends FillData {
 | 
			
		||||
    stEthTokenAddress: string;
 | 
			
		||||
    takerToken: string;
 | 
			
		||||
export interface NativeOrderFillData {
 | 
			
		||||
    order: LimitOrderFields | RfqOrderFields;
 | 
			
		||||
    signature: Signature;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a node on a fill path.
 | 
			
		||||
 */
 | 
			
		||||
export interface Fill<TFillData extends FillData = FillData> {
 | 
			
		||||
export interface Fill {
 | 
			
		||||
    // basic data for every fill
 | 
			
		||||
    source: ERC20BridgeSource;
 | 
			
		||||
    // TODO jacob people seem to agree  that orderType here is more readable
 | 
			
		||||
    type: FillQuoteTransformerOrderType; // should correspond with TFillData
 | 
			
		||||
    fillData: TFillData;
 | 
			
		||||
    data?: any;
 | 
			
		||||
    // Unique ID of the original source path this fill belongs to.
 | 
			
		||||
    // This is generated when the path is generated and is useful to distinguish
 | 
			
		||||
    // paths that have the same `source` IDs but are distinct (e.g., Curves).
 | 
			
		||||
@@ -295,15 +233,37 @@ export interface Fill<TFillData extends FillData = FillData> {
 | 
			
		||||
    parent?: Fill;
 | 
			
		||||
    // The index of the fill in the original path.
 | 
			
		||||
    index: number;
 | 
			
		||||
    // Cumulative gas cost associated with swapping against this source/pool.
 | 
			
		||||
    gasCost: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BridgeFill<TData extends BridgeFillData> extends Fill {
 | 
			
		||||
    data: TData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface GenericBridgeFill extends BridgeFill<BridgeFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface  UniswapV2BridgeFill extends BridgeFill<UniswapV2FillData> {}
 | 
			
		||||
 | 
			
		||||
export interface  UniswapV3BridgeFill extends BridgeFill<UniswapV3FillData> {}
 | 
			
		||||
 | 
			
		||||
export interface  LiquidityProviderBridgeFill extends BridgeFill<LiquidityProviderFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface  CurveBridgeFill extends BridgeFill<CurveFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface  MooniswapBridgeFill extends BridgeFill<MooniswapFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface NativeOrderFill extends Fill {
 | 
			
		||||
    data: NativeOrderFillData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents continguous fills on a path that have been merged together.
 | 
			
		||||
 */
 | 
			
		||||
export interface CollapsedFill<TFillData extends FillData = FillData> {
 | 
			
		||||
export interface CollapsedFill {
 | 
			
		||||
    source: ERC20BridgeSource;
 | 
			
		||||
    type: FillQuoteTransformerOrderType; // should correspond with TFillData
 | 
			
		||||
    fillData: TFillData;
 | 
			
		||||
    data?: any;
 | 
			
		||||
    // Unique ID of the original source path this fill belongs to.
 | 
			
		||||
    // This is generated when the path is generated and is useful to distinguish
 | 
			
		||||
    // paths that have the same `source` IDs but are distinct (e.g., Curves).
 | 
			
		||||
@@ -323,56 +283,68 @@ export interface CollapsedFill<TFillData extends FillData = FillData> {
 | 
			
		||||
        input: BigNumber;
 | 
			
		||||
        output: BigNumber;
 | 
			
		||||
    }>;
 | 
			
		||||
    gasCost: number;
 | 
			
		||||
    isFallback: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A `CollapsedFill` wrapping a native order.
 | 
			
		||||
 */
 | 
			
		||||
export interface NativeCollapsedFill extends CollapsedFill<NativeFillData> {}
 | 
			
		||||
export interface CollapsedBridgeFill<TData extends BridgeFillData> extends CollapsedFill {
 | 
			
		||||
    data: TData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface OptimizedMarketOrderBase<TFillData extends FillData = FillData> {
 | 
			
		||||
export interface CollapsedGenericBridgeFill extends CollapsedBridgeFill<BridgeFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface CollapsedUniswapV2BridgeFill extends CollapsedBridgeFill<UniswapV2FillData> {}
 | 
			
		||||
 | 
			
		||||
export interface CollapsedUniswapV3BridgeFill extends CollapsedBridgeFill<UniswapV3FillData> {}
 | 
			
		||||
 | 
			
		||||
export interface CollapsedLiquidityProviderBridgeFill extends CollapsedBridgeFill<LiquidityProviderFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface CollapsedCurveBridgeFill extends CollapsedBridgeFill<CurveFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface CollapsedMooniswapBridgeFill extends CollapsedBridgeFill<MooniswapFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface CollapsedNativeOrderFill extends CollapsedFill {
 | 
			
		||||
    data: NativeOrderFillData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface OptimizedOrder {
 | 
			
		||||
    source: ERC20BridgeSource;
 | 
			
		||||
    fillData: TFillData;
 | 
			
		||||
    type: FillQuoteTransformerOrderType; // should correspond with TFillData
 | 
			
		||||
    makerToken: string;
 | 
			
		||||
    takerToken: string;
 | 
			
		||||
    makerAmount: BigNumber; // The amount we wish to buy from this order, e.g inclusive of any previous partial fill
 | 
			
		||||
    takerAmount: BigNumber; // The amount we wish to fill this for, e.g inclusive of any previous partial fill
 | 
			
		||||
    type: FillQuoteTransformerOrderType;
 | 
			
		||||
    inputToken: string;
 | 
			
		||||
    outputToken: string;
 | 
			
		||||
    gasCost: number;
 | 
			
		||||
    inputAmount: BigNumber;
 | 
			
		||||
    outputAmount: BigNumber;
 | 
			
		||||
    fills: CollapsedFill[];
 | 
			
		||||
    isFallback: boolean;
 | 
			
		||||
    fillData: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface OptimizedMarketBridgeOrder<TFillData extends FillData = FillData>
 | 
			
		||||
    extends OptimizedMarketOrderBase<TFillData> {
 | 
			
		||||
export interface OptimizedBridgeOrder<TFillData extends BridgeFillData> extends OptimizedOrder {
 | 
			
		||||
    type: FillQuoteTransformerOrderType.Bridge;
 | 
			
		||||
    fillData: TFillData;
 | 
			
		||||
    sourcePathId: string;
 | 
			
		||||
    fillData: TFillData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface OptimizedLimitOrder extends OptimizedMarketOrderBase<NativeLimitOrderFillData> {
 | 
			
		||||
export interface OptimizedGenericBridgeOrder extends OptimizedBridgeOrder<BridgeFillData> {}
 | 
			
		||||
 | 
			
		||||
export interface OptimizedUniswapV2BridgeOrder extends OptimizedBridgeOrder<UniswapV2FillData> {}
 | 
			
		||||
 | 
			
		||||
export interface OptimizedLimitOrder extends OptimizedOrder {
 | 
			
		||||
    type: FillQuoteTransformerOrderType.Limit;
 | 
			
		||||
    fillData: NativeLimitOrderFillData;
 | 
			
		||||
    fillData: Omit<NativeOrderFillData, 'type'>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface OptimizedRfqOrder extends OptimizedMarketOrderBase<NativeRfqOrderFillData> {
 | 
			
		||||
export interface OptimizedRfqOrder extends OptimizedOrder {
 | 
			
		||||
    type: FillQuoteTransformerOrderType.Rfq;
 | 
			
		||||
    fillData: NativeRfqOrderFillData;
 | 
			
		||||
    fillData: Omit<NativeOrderFillData, 'type'>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Optimized orders to fill.
 | 
			
		||||
 */
 | 
			
		||||
export type OptimizedMarketOrder =
 | 
			
		||||
    | OptimizedMarketBridgeOrder<FillData>
 | 
			
		||||
    | OptimizedMarketOrderBase<NativeLimitOrderFillData>
 | 
			
		||||
    | OptimizedMarketOrderBase<NativeRfqOrderFillData>;
 | 
			
		||||
 | 
			
		||||
export interface GetMarketOrdersRfqOpts extends RfqRequestOpts {
 | 
			
		||||
    quoteRequestor?: QuoteRequestor;
 | 
			
		||||
    firmQuoteValidator?: RfqFirmQuoteValidator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type FeeEstimate = (fillData: FillData) => number | BigNumber;
 | 
			
		||||
export type FeeSchedule = Partial<{ [key in ERC20BridgeSource]: FeeEstimate }>;
 | 
			
		||||
export type ExchangeProxyOverhead = (sourceFlags: bigint) => BigNumber;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -413,26 +385,6 @@ export interface GetMarketOrdersOpts {
 | 
			
		||||
     * percentage, no fallback quote will be provided.
 | 
			
		||||
     */
 | 
			
		||||
    maxFallbackSlippage: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * Number of samples to take for each DEX quote.
 | 
			
		||||
     */
 | 
			
		||||
    numSamples: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * The exponential sampling distribution base.
 | 
			
		||||
     * A value of 1 will result in evenly spaced samples.
 | 
			
		||||
     * > 1 will result in more samples at lower sizes.
 | 
			
		||||
     * < 1 will result in more samples at higher sizes.
 | 
			
		||||
     * Default: 1.25.
 | 
			
		||||
     */
 | 
			
		||||
    sampleDistributionBase: number;
 | 
			
		||||
    /**
 | 
			
		||||
     * Fees for each liquidity source, expressed in gas.
 | 
			
		||||
     */
 | 
			
		||||
    feeSchedule: FeeSchedule;
 | 
			
		||||
    /**
 | 
			
		||||
     * Estimated gas consumed by each liquidity source.
 | 
			
		||||
     */
 | 
			
		||||
    gasSchedule: FeeSchedule;
 | 
			
		||||
    exchangeProxyOverhead: ExchangeProxyOverhead;
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to pad the quote with a redundant fallback quote using different
 | 
			
		||||
@@ -473,17 +425,21 @@ export interface BatchedOperation<TResult> {
 | 
			
		||||
    handleRevert(callResults: string): TResult;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SourceQuoteOperation<TFillData extends FillData = FillData> extends BatchedOperation<BigNumber[]> {
 | 
			
		||||
    readonly source: ERC20BridgeSource;
 | 
			
		||||
    fillData: TFillData;
 | 
			
		||||
export interface OptimizedHop {
 | 
			
		||||
    inputToken: Address;
 | 
			
		||||
    outputToken: Address;
 | 
			
		||||
    inputAmount: BigNumber;
 | 
			
		||||
    outputAmount: BigNumber;
 | 
			
		||||
    sourceFlags: bigint;
 | 
			
		||||
    orders: OptimizedOrder[];
 | 
			
		||||
    adjustedCompleteRate: BigNumber;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface OptimizerResult {
 | 
			
		||||
    optimizedOrders: OptimizedMarketOrder[];
 | 
			
		||||
    sourceFlags: bigint;
 | 
			
		||||
    liquidityDelivered: CollapsedFill[] | DexSample<MultiHopFillData>;
 | 
			
		||||
    marketSideLiquidity: MarketSideLiquidity;
 | 
			
		||||
    adjustedRate: BigNumber;
 | 
			
		||||
    hops: OptimizedHop[];
 | 
			
		||||
    // liquidityDelivered: CollapsedFill[] | DexSample<MultiHopFillData>;
 | 
			
		||||
    marketSideLiquidity: MarketSideLiquidity;
 | 
			
		||||
    unoptimizedPath?: CollapsedPath;
 | 
			
		||||
    takerAmountPerEth: BigNumber;
 | 
			
		||||
    makerAmountPerEth: BigNumber;
 | 
			
		||||
@@ -494,7 +450,7 @@ export interface OptimizerResultWithReport extends OptimizerResult {
 | 
			
		||||
    priceComparisonsReport?: PriceComparisonsReport;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type MarketDepthSide = Array<Array<DexSample<FillData>>>;
 | 
			
		||||
export type MarketDepthSide = Array<Array<DexSample>>;
 | 
			
		||||
 | 
			
		||||
export interface MarketDepth {
 | 
			
		||||
    bids: MarketDepthSide;
 | 
			
		||||
@@ -503,25 +459,29 @@ export interface MarketDepth {
 | 
			
		||||
    takerTokenDecimals: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface TokenAmountPerEth {
 | 
			
		||||
    [tokenAddress: string]: BigNumber;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MarketSideLiquidity {
 | 
			
		||||
    side: MarketOperation;
 | 
			
		||||
    inputAmount: BigNumber;
 | 
			
		||||
    inputToken: string;
 | 
			
		||||
    outputToken: string;
 | 
			
		||||
    outputAmountPerEth: BigNumber;
 | 
			
		||||
    inputAmountPerEth: BigNumber;
 | 
			
		||||
    tokenAmountPerEth: TokenAmountPerEth;
 | 
			
		||||
    quoteSourceFilters: SourceFilters;
 | 
			
		||||
    makerTokenDecimals: number;
 | 
			
		||||
    takerTokenDecimals: number;
 | 
			
		||||
    quotes: RawQuotes;
 | 
			
		||||
    quotes: RawHopQuotes[];
 | 
			
		||||
    isRfqSupported: boolean;
 | 
			
		||||
    gasPrice: BigNumber;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface RawQuotes {
 | 
			
		||||
export interface RawHopQuotes {
 | 
			
		||||
    inputToken: Address;
 | 
			
		||||
    outputToken: Address;
 | 
			
		||||
    nativeOrders: NativeOrderWithFillableAmounts[];
 | 
			
		||||
    rfqtIndicativeQuotes: V4RFQIndicativeQuote[];
 | 
			
		||||
    twoHopQuotes: Array<DexSample<MultiHopFillData>>;
 | 
			
		||||
    dexQuotes: Array<Array<DexSample<FillData>>>;
 | 
			
		||||
    dexQuotes: DexSample[][];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface TokenAdjacencyGraph {
 | 
			
		||||
@@ -541,7 +501,6 @@ export interface GenerateOptimizedOrdersOpts {
 | 
			
		||||
    bridgeSlippage?: number;
 | 
			
		||||
    maxFallbackSlippage?: number;
 | 
			
		||||
    excludedSources?: ERC20BridgeSource[];
 | 
			
		||||
    feeSchedule: FeeSchedule;
 | 
			
		||||
    exchangeProxyOverhead?: ExchangeProxyOverhead;
 | 
			
		||||
    allowFallback?: boolean;
 | 
			
		||||
    shouldBatchBridgeOrders?: boolean;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								packages/asset-swapper/src/utils/native_orders.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								packages/asset-swapper/src/utils/native_orders.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import {
 | 
			
		||||
    CommonOrderFields,
 | 
			
		||||
    FillQuoteTransformerOrderType,
 | 
			
		||||
    LimitOrderFields,
 | 
			
		||||
    RfqOrderFields,
 | 
			
		||||
    Signature,
 | 
			
		||||
} from '@0x/protocol-utils';
 | 
			
		||||
 | 
			
		||||
import { SignedNativeOrder } from '../types';
 | 
			
		||||
 | 
			
		||||
export interface SignedOrder<T> {
 | 
			
		||||
    order: T;
 | 
			
		||||
    type: FillQuoteTransformerOrderType.Limit | FillQuoteTransformerOrderType.Rfq;
 | 
			
		||||
    signature: Signature;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type NativeOrderWithFillableAmounts = SignedNativeOrder & NativeOrderFillableAmountFields & {
 | 
			
		||||
    gasCost: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * fillableMakerAmount: Amount of makerAsset that is fillable
 | 
			
		||||
 * fillableTakerAmount: Amount of takerAsset that is fillable
 | 
			
		||||
 * fillableTakerFeeAmount: Amount of takerFee paid to fill fillableTakerAmount
 | 
			
		||||
 */
 | 
			
		||||
export interface NativeOrderFillableAmountFields {
 | 
			
		||||
    fillableMakerAmount: BigNumber;
 | 
			
		||||
    fillableTakerAmount: BigNumber;
 | 
			
		||||
    fillableTakerFeeAmount: BigNumber;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import * as heartbeats from 'heartbeats';
 | 
			
		||||
import fetch from 'axios';
 | 
			
		||||
 | 
			
		||||
import { constants } from '../constants';
 | 
			
		||||
import { SwapQuoterError } from '../types';
 | 
			
		||||
@@ -61,7 +62,7 @@ export class ProtocolFeeUtils {
 | 
			
		||||
    private async _getGasPriceFromGasStationOrThrowAsync(): Promise<BigNumber> {
 | 
			
		||||
        try {
 | 
			
		||||
            const res = await fetch(this._ethGasStationUrl);
 | 
			
		||||
            const gasInfo = await res.json();
 | 
			
		||||
            const gasInfo = res.data;
 | 
			
		||||
            // Eth Gas Station result is gwei * 10
 | 
			
		||||
            // tslint:disable-next-line:custom-no-magic-numbers
 | 
			
		||||
            const BASE_TEN = 10;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,26 +2,22 @@ import { FillQuoteTransformerOrderType, RfqOrderFields, Signature } from '@0x/pr
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import _ = require('lodash');
 | 
			
		||||
 | 
			
		||||
import { MarketOperation, NativeOrderWithFillableAmounts } from '../types';
 | 
			
		||||
import { MarketOperation } from '../types';
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
    CollapsedFill,
 | 
			
		||||
    DexSample,
 | 
			
		||||
    ERC20BridgeSource,
 | 
			
		||||
    FillData,
 | 
			
		||||
    MultiHopFillData,
 | 
			
		||||
    NativeCollapsedFill,
 | 
			
		||||
    NativeFillData,
 | 
			
		||||
    NativeLimitOrderFillData,
 | 
			
		||||
    NativeRfqOrderFillData,
 | 
			
		||||
    CollapsedNativeOrderFill,
 | 
			
		||||
} from './market_operation_utils/types';
 | 
			
		||||
import { NativeOrderWithFillableAmounts } from './native_orders';
 | 
			
		||||
import { QuoteRequestor } from './quote_requestor';
 | 
			
		||||
 | 
			
		||||
export interface QuoteReportEntryBase {
 | 
			
		||||
    liquiditySource: ERC20BridgeSource;
 | 
			
		||||
    makerAmount: BigNumber;
 | 
			
		||||
    takerAmount: BigNumber;
 | 
			
		||||
    fillData: FillData;
 | 
			
		||||
    fillData: any;
 | 
			
		||||
}
 | 
			
		||||
export interface BridgeQuoteReportEntry extends QuoteReportEntryBase {
 | 
			
		||||
    liquiditySource: Exclude<ERC20BridgeSource, ERC20BridgeSource.Native>;
 | 
			
		||||
@@ -34,14 +30,14 @@ export interface MultiHopQuoteReportEntry extends QuoteReportEntryBase {
 | 
			
		||||
 | 
			
		||||
export interface NativeLimitOrderQuoteReportEntry extends QuoteReportEntryBase {
 | 
			
		||||
    liquiditySource: ERC20BridgeSource.Native;
 | 
			
		||||
    fillData: NativeFillData;
 | 
			
		||||
    fillData: any;
 | 
			
		||||
    fillableTakerAmount: BigNumber;
 | 
			
		||||
    isRfqt: false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface NativeRfqOrderQuoteReportEntry extends QuoteReportEntryBase {
 | 
			
		||||
    liquiditySource: ERC20BridgeSource.Native;
 | 
			
		||||
    fillData: NativeFillData;
 | 
			
		||||
    fillData: any;
 | 
			
		||||
    fillableTakerAmount: BigNumber;
 | 
			
		||||
    isRfqt: true;
 | 
			
		||||
    nativeOrder: RfqOrderFields;
 | 
			
		||||
@@ -73,47 +69,48 @@ export interface PriceComparisonsReport {
 | 
			
		||||
export function generateQuoteReport(
 | 
			
		||||
    marketOperation: MarketOperation,
 | 
			
		||||
    nativeOrders: NativeOrderWithFillableAmounts[],
 | 
			
		||||
    liquidityDelivered: ReadonlyArray<CollapsedFill> | DexSample<MultiHopFillData>,
 | 
			
		||||
    // liquidityDelivered: ReadonlyArray<CollapsedFill> | DexSample<MultiHopFillData>,
 | 
			
		||||
    comparisonPrice?: BigNumber | undefined,
 | 
			
		||||
    quoteRequestor?: QuoteRequestor,
 | 
			
		||||
): QuoteReport {
 | 
			
		||||
    const nativeOrderSourcesConsidered = nativeOrders.map(order =>
 | 
			
		||||
        nativeOrderToReportEntry(order.type, order as any, order.fillableTakerAmount, comparisonPrice, quoteRequestor),
 | 
			
		||||
    );
 | 
			
		||||
    const sourcesConsidered = [...nativeOrderSourcesConsidered.filter(order => order.isRfqt)];
 | 
			
		||||
 | 
			
		||||
    let sourcesDelivered;
 | 
			
		||||
    if (Array.isArray(liquidityDelivered)) {
 | 
			
		||||
        // create easy way to look up fillable amounts
 | 
			
		||||
        const nativeOrderSignaturesToFillableAmounts = _.fromPairs(
 | 
			
		||||
            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),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
    return {
 | 
			
		||||
        sourcesConsidered,
 | 
			
		||||
        sourcesDelivered,
 | 
			
		||||
    };
 | 
			
		||||
    throw new Error(`Not implemented`);
 | 
			
		||||
    // const nativeOrderSourcesConsidered = nativeOrders.map(order =>
 | 
			
		||||
    //     nativeOrderToReportEntry(order.type, order as any, order.fillableTakerAmount, comparisonPrice, quoteRequestor),
 | 
			
		||||
    // );
 | 
			
		||||
    // const sourcesConsidered = [...nativeOrderSourcesConsidered.filter(order => order.isRfqt)];
 | 
			
		||||
    //
 | 
			
		||||
    // let sourcesDelivered;
 | 
			
		||||
    // if (Array.isArray(liquidityDelivered)) {
 | 
			
		||||
    //     // create easy way to look up fillable amounts
 | 
			
		||||
    //     const nativeOrderSignaturesToFillableAmounts = _.fromPairs(
 | 
			
		||||
    //         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),
 | 
			
		||||
    //     ];
 | 
			
		||||
    // }
 | 
			
		||||
    // return {
 | 
			
		||||
    //     sourcesConsidered,
 | 
			
		||||
    //     sourcesDelivered,
 | 
			
		||||
    // };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _nativeDataToId(data: { signature: Signature }): string {
 | 
			
		||||
@@ -126,31 +123,32 @@ function _nativeDataToId(data: { signature: Signature }): string {
 | 
			
		||||
 * NOTE: this is used for the QuoteReport and quote price comparison data
 | 
			
		||||
 */
 | 
			
		||||
export function dexSampleToReportSource(ds: DexSample, marketOperation: MarketOperation): BridgeQuoteReportEntry {
 | 
			
		||||
    const liquiditySource = ds.source;
 | 
			
		||||
 | 
			
		||||
    if (liquiditySource === ERC20BridgeSource.Native) {
 | 
			
		||||
        throw new Error(`Unexpected liquidity source Native`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // input and output map to different values
 | 
			
		||||
    // based on the market operation
 | 
			
		||||
    if (marketOperation === MarketOperation.Buy) {
 | 
			
		||||
        return {
 | 
			
		||||
            makerAmount: ds.input,
 | 
			
		||||
            takerAmount: ds.output,
 | 
			
		||||
            liquiditySource,
 | 
			
		||||
            fillData: ds.fillData,
 | 
			
		||||
        };
 | 
			
		||||
    } else if (marketOperation === MarketOperation.Sell) {
 | 
			
		||||
        return {
 | 
			
		||||
            makerAmount: ds.output,
 | 
			
		||||
            takerAmount: ds.input,
 | 
			
		||||
            liquiditySource,
 | 
			
		||||
            fillData: ds.fillData,
 | 
			
		||||
        };
 | 
			
		||||
    } else {
 | 
			
		||||
        throw new Error(`Unexpected marketOperation ${marketOperation}`);
 | 
			
		||||
    }
 | 
			
		||||
    throw new Error(`Not implemented`);
 | 
			
		||||
    // const liquiditySource = ds.source;
 | 
			
		||||
    //
 | 
			
		||||
    // if (liquiditySource === ERC20BridgeSource.Native) {
 | 
			
		||||
    //     throw new Error(`Unexpected liquidity source Native`);
 | 
			
		||||
    // }
 | 
			
		||||
    //
 | 
			
		||||
    // // input and output map to different values
 | 
			
		||||
    // // based on the market operation
 | 
			
		||||
    // if (marketOperation === MarketOperation.Buy) {
 | 
			
		||||
    //     return {
 | 
			
		||||
    //         makerAmount: ds.input,
 | 
			
		||||
    //         takerAmount: ds.output,
 | 
			
		||||
    //         liquiditySource,
 | 
			
		||||
    //         fillData: ds.fillData,
 | 
			
		||||
    //     };
 | 
			
		||||
    // } else if (marketOperation === MarketOperation.Sell) {
 | 
			
		||||
    //     return {
 | 
			
		||||
    //         makerAmount: ds.output,
 | 
			
		||||
    //         takerAmount: ds.input,
 | 
			
		||||
    //         liquiditySource,
 | 
			
		||||
    //         fillData: ds.fillData,
 | 
			
		||||
    //     };
 | 
			
		||||
    // } else {
 | 
			
		||||
    //     throw new Error(`Unexpected marketOperation ${marketOperation}`);
 | 
			
		||||
    // }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -158,34 +156,35 @@ export function dexSampleToReportSource(ds: DexSample, marketOperation: MarketOp
 | 
			
		||||
 * NOTE: this is used for the QuoteReport and quote price comparison data
 | 
			
		||||
 */
 | 
			
		||||
export function multiHopSampleToReportSource(
 | 
			
		||||
    ds: DexSample<MultiHopFillData>,
 | 
			
		||||
    ds: DexSample,
 | 
			
		||||
    marketOperation: MarketOperation,
 | 
			
		||||
): MultiHopQuoteReportEntry {
 | 
			
		||||
    const { firstHopSource: firstHop, secondHopSource: secondHop } = ds.fillData;
 | 
			
		||||
    // input and output map to different values
 | 
			
		||||
    // based on the market operation
 | 
			
		||||
    if (marketOperation === MarketOperation.Buy) {
 | 
			
		||||
        return {
 | 
			
		||||
            liquiditySource: ERC20BridgeSource.MultiHop,
 | 
			
		||||
            makerAmount: ds.input,
 | 
			
		||||
            takerAmount: ds.output,
 | 
			
		||||
            fillData: ds.fillData,
 | 
			
		||||
            hopSources: [firstHop.source, secondHop.source],
 | 
			
		||||
        };
 | 
			
		||||
    } else if (marketOperation === MarketOperation.Sell) {
 | 
			
		||||
        return {
 | 
			
		||||
            liquiditySource: ERC20BridgeSource.MultiHop,
 | 
			
		||||
            makerAmount: ds.output,
 | 
			
		||||
            takerAmount: ds.input,
 | 
			
		||||
            fillData: ds.fillData,
 | 
			
		||||
            hopSources: [firstHop.source, secondHop.source],
 | 
			
		||||
        };
 | 
			
		||||
    } else {
 | 
			
		||||
        throw new Error(`Unexpected marketOperation ${marketOperation}`);
 | 
			
		||||
    }
 | 
			
		||||
    throw new Error(`Not implemented`);
 | 
			
		||||
    // const { firstHopSource: firstHop, secondHopSource: secondHop } = ds.fillData;
 | 
			
		||||
    // // input and output map to different values
 | 
			
		||||
    // // based on the market operation
 | 
			
		||||
    // if (marketOperation === MarketOperation.Buy) {
 | 
			
		||||
    //     return {
 | 
			
		||||
    //         liquiditySource: ERC20BridgeSource.MultiHop,
 | 
			
		||||
    //         makerAmount: ds.input,
 | 
			
		||||
    //         takerAmount: ds.output,
 | 
			
		||||
    //         fillData: ds.fillData,
 | 
			
		||||
    //         hopSources: [firstHop.source, secondHop.source],
 | 
			
		||||
    //     };
 | 
			
		||||
    // } else if (marketOperation === MarketOperation.Sell) {
 | 
			
		||||
    //     return {
 | 
			
		||||
    //         liquiditySource: ERC20BridgeSource.MultiHop,
 | 
			
		||||
    //         makerAmount: ds.output,
 | 
			
		||||
    //         takerAmount: ds.input,
 | 
			
		||||
    //         fillData: ds.fillData,
 | 
			
		||||
    //         hopSources: [firstHop.source, secondHop.source],
 | 
			
		||||
    //     };
 | 
			
		||||
    // } else {
 | 
			
		||||
    //     throw new Error(`Unexpected marketOperation ${marketOperation}`);
 | 
			
		||||
    // }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _isNativeOrderFromCollapsedFill(cf: CollapsedFill): cf is NativeCollapsedFill {
 | 
			
		||||
function _isNativeOrderFromCollapsedFill(cf: CollapsedFill): cf is CollapsedNativeOrderFill {
 | 
			
		||||
    const { type } = cf;
 | 
			
		||||
    return type === FillQuoteTransformerOrderType.Limit || type === FillQuoteTransformerOrderType.Rfq;
 | 
			
		||||
}
 | 
			
		||||
@@ -196,41 +195,42 @@ function _isNativeOrderFromCollapsedFill(cf: CollapsedFill): cf is NativeCollaps
 | 
			
		||||
 */
 | 
			
		||||
export function nativeOrderToReportEntry(
 | 
			
		||||
    type: FillQuoteTransformerOrderType,
 | 
			
		||||
    fillData: NativeLimitOrderFillData | NativeRfqOrderFillData,
 | 
			
		||||
    fillData: any,
 | 
			
		||||
    fillableAmount: BigNumber,
 | 
			
		||||
    comparisonPrice?: BigNumber | undefined,
 | 
			
		||||
    quoteRequestor?: QuoteRequestor,
 | 
			
		||||
): NativeRfqOrderQuoteReportEntry | NativeLimitOrderQuoteReportEntry {
 | 
			
		||||
    const nativeOrderBase = {
 | 
			
		||||
        makerAmount: fillData.order.makerAmount,
 | 
			
		||||
        takerAmount: fillData.order.takerAmount,
 | 
			
		||||
        fillableTakerAmount: fillableAmount,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // if we find this is an rfqt order, label it as such and associate makerUri
 | 
			
		||||
    const isRfqt = type === FillQuoteTransformerOrderType.Rfq;
 | 
			
		||||
    const rfqtMakerUri =
 | 
			
		||||
        isRfqt && quoteRequestor ? quoteRequestor.getMakerUriForSignature(fillData.signature) : undefined;
 | 
			
		||||
 | 
			
		||||
    if (isRfqt) {
 | 
			
		||||
        const nativeOrder = fillData.order as RfqOrderFields;
 | 
			
		||||
        // tslint:disable-next-line: no-object-literal-type-assertion
 | 
			
		||||
        return {
 | 
			
		||||
            liquiditySource: ERC20BridgeSource.Native,
 | 
			
		||||
            ...nativeOrderBase,
 | 
			
		||||
            isRfqt: true,
 | 
			
		||||
            makerUri: rfqtMakerUri || '',
 | 
			
		||||
            ...(comparisonPrice ? { comparisonPrice: comparisonPrice.toNumber() } : {}),
 | 
			
		||||
            nativeOrder,
 | 
			
		||||
            fillData,
 | 
			
		||||
        };
 | 
			
		||||
    } else {
 | 
			
		||||
        // tslint:disable-next-line: no-object-literal-type-assertion
 | 
			
		||||
        return {
 | 
			
		||||
            liquiditySource: ERC20BridgeSource.Native,
 | 
			
		||||
            ...nativeOrderBase,
 | 
			
		||||
            isRfqt: false,
 | 
			
		||||
            fillData,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
    throw new Error(`Not implemented`);
 | 
			
		||||
    // const nativeOrderBase = {
 | 
			
		||||
    //     makerAmount: fillData.order.makerAmount,
 | 
			
		||||
    //     takerAmount: fillData.order.takerAmount,
 | 
			
		||||
    //     fillableTakerAmount: fillableAmount,
 | 
			
		||||
    // };
 | 
			
		||||
    //
 | 
			
		||||
    // // if we find this is an rfqt order, label it as such and associate makerUri
 | 
			
		||||
    // const isRfqt = type === FillQuoteTransformerOrderType.Rfq;
 | 
			
		||||
    // const rfqtMakerUri =
 | 
			
		||||
    //     isRfqt && quoteRequestor ? quoteRequestor.getMakerUriForSignature(fillData.signature) : undefined;
 | 
			
		||||
    //
 | 
			
		||||
    // if (isRfqt) {
 | 
			
		||||
    //     const nativeOrder = fillData.order as RfqOrderFields;
 | 
			
		||||
    //     // tslint:disable-next-line: no-object-literal-type-assertion
 | 
			
		||||
    //     return {
 | 
			
		||||
    //         liquiditySource: ERC20BridgeSource.Native,
 | 
			
		||||
    //         ...nativeOrderBase,
 | 
			
		||||
    //         isRfqt: true,
 | 
			
		||||
    //         makerUri: rfqtMakerUri || '',
 | 
			
		||||
    //         ...(comparisonPrice ? { comparisonPrice: comparisonPrice.toNumber() } : {}),
 | 
			
		||||
    //         nativeOrder,
 | 
			
		||||
    //         fillData,
 | 
			
		||||
    //     };
 | 
			
		||||
    // } else {
 | 
			
		||||
    //     // tslint:disable-next-line: no-object-literal-type-assertion
 | 
			
		||||
    //     return {
 | 
			
		||||
    //         liquiditySource: ERC20BridgeSource.Native,
 | 
			
		||||
    //         ...nativeOrderBase,
 | 
			
		||||
    //         isRfqt: false,
 | 
			
		||||
    //         fillData,
 | 
			
		||||
    //     };
 | 
			
		||||
    // }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ import {
 | 
			
		||||
    RfqmRequestOptions,
 | 
			
		||||
    RfqPairType,
 | 
			
		||||
    RfqRequestOpts,
 | 
			
		||||
    SignedNativeOrder,
 | 
			
		||||
    SignedRfqOrder,
 | 
			
		||||
    TypedMakerUrl,
 | 
			
		||||
} from '../types';
 | 
			
		||||
 | 
			
		||||
@@ -282,7 +282,7 @@ export class QuoteRequestor {
 | 
			
		||||
        private readonly _altRfqCreds?: { altRfqApiKey: string; altRfqProfile: string },
 | 
			
		||||
        private readonly _warningLogger: LogFunction = constants.DEFAULT_WARNING_LOGGER,
 | 
			
		||||
        private readonly _infoLogger: LogFunction = constants.DEFAULT_INFO_LOGGER,
 | 
			
		||||
        private readonly _expiryBufferMs: number = constants.DEFAULT_SWAP_QUOTER_OPTS.expiryBufferMs,
 | 
			
		||||
        private readonly _expiryBufferMs: number = 120e3,
 | 
			
		||||
        private readonly _metrics?: MetricsProxy,
 | 
			
		||||
    ) {
 | 
			
		||||
        rfqMakerBlacklist.infoLogger = this._infoLogger;
 | 
			
		||||
@@ -295,7 +295,7 @@ export class QuoteRequestor {
 | 
			
		||||
        marketOperation: MarketOperation,
 | 
			
		||||
        comparisonPrice: BigNumber | undefined,
 | 
			
		||||
        options: RfqmRequestOptions,
 | 
			
		||||
    ): Promise<SignedNativeOrder[]> {
 | 
			
		||||
    ): Promise<SignedRfqOrder[]> {
 | 
			
		||||
        const _opts: RfqRequestOpts = {
 | 
			
		||||
            ...constants.DEFAULT_RFQT_REQUEST_OPTS,
 | 
			
		||||
            ...options,
 | 
			
		||||
@@ -319,7 +319,7 @@ export class QuoteRequestor {
 | 
			
		||||
        marketOperation: MarketOperation,
 | 
			
		||||
        comparisonPrice: BigNumber | undefined,
 | 
			
		||||
        options: RfqRequestOpts,
 | 
			
		||||
    ): Promise<SignedNativeOrder[]> {
 | 
			
		||||
    ): Promise<SignedRfqOrder[]> {
 | 
			
		||||
        const _opts: RfqRequestOpts = { ...constants.DEFAULT_RFQT_REQUEST_OPTS, ...options };
 | 
			
		||||
        if (!_opts.txOrigin || [undefined, '', '0x', NULL_ADDRESS].includes(_opts.txOrigin)) {
 | 
			
		||||
            throw new Error('RFQ-T firm quotes require the presence of a tx origin');
 | 
			
		||||
@@ -642,7 +642,7 @@ export class QuoteRequestor {
 | 
			
		||||
        comparisonPrice: BigNumber | undefined,
 | 
			
		||||
        options: RfqRequestOpts,
 | 
			
		||||
        assetOfferings: RfqMakerAssetOfferings,
 | 
			
		||||
    ): Promise<SignedNativeOrder[]> {
 | 
			
		||||
    ): Promise<SignedRfqOrder[]> {
 | 
			
		||||
        const quotesRaw = await this._getQuotesAsync<V4RFQFirmQuote>(
 | 
			
		||||
            makerToken,
 | 
			
		||||
            takerToken,
 | 
			
		||||
@@ -719,7 +719,7 @@ export class QuoteRequestor {
 | 
			
		||||
        // Save the maker URI for later and return just the order
 | 
			
		||||
        const rfqQuotes = validQuotes.map(result => {
 | 
			
		||||
            const { signature, ...rest } = result.response;
 | 
			
		||||
            const order: SignedNativeOrder = {
 | 
			
		||||
            const order: SignedRfqOrder = {
 | 
			
		||||
                order: {
 | 
			
		||||
                    ...rest,
 | 
			
		||||
                    makerAmount: new BigNumber(result.response.makerAmount),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,8 @@
 | 
			
		||||
import { FillQuoteTransformerOrderType } from '@0x/protocol-utils';
 | 
			
		||||
import { FillQuoteTransformerOrderType, LimitOrderFields } from '@0x/protocol-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { constants } from '../constants';
 | 
			
		||||
import { MarketOperation } from '../types';
 | 
			
		||||
 | 
			
		||||
import { FeeSchedule, NativeLimitOrderFillData, OptimizedMarketOrder } from './market_operation_utils/types';
 | 
			
		||||
import { getNativeAdjustedTakerFeeAmount } from './utils';
 | 
			
		||||
import { MarketOperation, SwapQuoteLimitOrder, SwapQuoteOrder } from '../types';
 | 
			
		||||
 | 
			
		||||
const { PROTOCOL_FEE_MULTIPLIER, ZERO_AMOUNT } = constants;
 | 
			
		||||
const { ROUND_DOWN, ROUND_UP } = BigNumber;
 | 
			
		||||
@@ -64,7 +61,7 @@ const EMPTY_QUOTE_INTERMEDIATE_FILL_RESULT = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface QuoteFillInfo {
 | 
			
		||||
    orders: OptimizedMarketOrder[];
 | 
			
		||||
    orders: SwapQuoteOrder[];
 | 
			
		||||
    fillAmount: BigNumber;
 | 
			
		||||
    gasPrice: BigNumber;
 | 
			
		||||
    side: MarketOperation;
 | 
			
		||||
@@ -72,19 +69,17 @@ export interface QuoteFillInfo {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface QuoteFillInfoOpts {
 | 
			
		||||
    gasSchedule: FeeSchedule;
 | 
			
		||||
    protocolFeeMultiplier: BigNumber;
 | 
			
		||||
    slippage: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const DEFAULT_SIMULATED_FILL_QUOTE_INFO_OPTS: QuoteFillInfoOpts = {
 | 
			
		||||
    gasSchedule: {},
 | 
			
		||||
    protocolFeeMultiplier: PROTOCOL_FEE_MULTIPLIER,
 | 
			
		||||
    slippage: 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface QuoteFillOrderCall {
 | 
			
		||||
    order: OptimizedMarketOrder;
 | 
			
		||||
    order: SwapQuoteOrder;
 | 
			
		||||
    // Total input amount defined in the order.
 | 
			
		||||
    totalOrderInput: BigNumber;
 | 
			
		||||
    // Total output amount defined in the order.
 | 
			
		||||
@@ -108,7 +103,6 @@ export function simulateBestCaseFill(quoteInfo: QuoteFillInfo): QuoteFillResult
 | 
			
		||||
        createBestCaseFillOrderCalls(quoteInfo),
 | 
			
		||||
        quoteInfo.fillAmount,
 | 
			
		||||
        protocolFeePerFillOrder,
 | 
			
		||||
        opts.gasSchedule,
 | 
			
		||||
    );
 | 
			
		||||
    return fromIntermediateQuoteFillResult(result, quoteInfo);
 | 
			
		||||
}
 | 
			
		||||
@@ -122,9 +116,9 @@ export function simulateWorstCaseFill(quoteInfo: QuoteFillInfo): QuoteFillResult
 | 
			
		||||
    const protocolFeePerFillOrder = quoteInfo.gasPrice.times(opts.protocolFeeMultiplier);
 | 
			
		||||
    const bestCase = createBestCaseFillOrderCalls(quoteInfo);
 | 
			
		||||
    const result = {
 | 
			
		||||
        ...fillQuoteOrders(bestCase, quoteInfo.fillAmount, protocolFeePerFillOrder, opts.gasSchedule),
 | 
			
		||||
        ...fillQuoteOrders(bestCase, quoteInfo.fillAmount, protocolFeePerFillOrder),
 | 
			
		||||
        // Worst case gas and protocol fee is hitting all orders.
 | 
			
		||||
        gas: getTotalGasUsedByFills(quoteInfo.orders, opts.gasSchedule),
 | 
			
		||||
        gas: getTotalGasUsedByFills(quoteInfo.orders),
 | 
			
		||||
        protocolFee: protocolFeePerFillOrder.times(quoteInfo.orders.filter(o => hasProtocolFee(o)).length),
 | 
			
		||||
    };
 | 
			
		||||
    // Adjust the output by 1-slippage for the worst case if it is a sell
 | 
			
		||||
@@ -140,7 +134,6 @@ export function fillQuoteOrders(
 | 
			
		||||
    fillOrders: QuoteFillOrderCall[],
 | 
			
		||||
    inputAmount: BigNumber,
 | 
			
		||||
    protocolFeePerFillOrder: BigNumber,
 | 
			
		||||
    gasSchedule: FeeSchedule,
 | 
			
		||||
): IntermediateQuoteFillResult {
 | 
			
		||||
    const result: IntermediateQuoteFillResult = {
 | 
			
		||||
        ...EMPTY_QUOTE_INTERMEDIATE_FILL_RESULT,
 | 
			
		||||
@@ -151,39 +144,27 @@ export function fillQuoteOrders(
 | 
			
		||||
        if (remainingInput.lte(0)) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        for (const fill of fo.order.fills) {
 | 
			
		||||
            if (remainingInput.lte(0)) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            const { source, fillData } = fill;
 | 
			
		||||
            const gas = gasSchedule[source] === undefined ? 0 : gasSchedule[source]!(fillData);
 | 
			
		||||
            result.gas += new BigNumber(gas).toNumber();
 | 
			
		||||
            result.inputBySource[source] = result.inputBySource[source] || ZERO_AMOUNT;
 | 
			
		||||
        const { source } = fo.order;
 | 
			
		||||
        result.gas += fo.order.gasCost;
 | 
			
		||||
        result.inputBySource[source] = result.inputBySource[source] || ZERO_AMOUNT;
 | 
			
		||||
 | 
			
		||||
            // Actual rates are rarely linear, so fill subfills individually to
 | 
			
		||||
            // get a better approximation of fill size.
 | 
			
		||||
            for (const subFill of fill.subFills) {
 | 
			
		||||
                if (remainingInput.lte(0)) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                const filledInput = solveForInputFillAmount(
 | 
			
		||||
                    remainingInput,
 | 
			
		||||
                    subFill.input,
 | 
			
		||||
                    fo.totalOrderInput,
 | 
			
		||||
                    fo.totalOrderInputFee,
 | 
			
		||||
                );
 | 
			
		||||
                const filledOutput = subFill.output.times(filledInput.div(subFill.input));
 | 
			
		||||
                const filledInputFee = filledInput.div(fo.totalOrderInput).times(fo.totalOrderInputFee);
 | 
			
		||||
                const filledOutputFee = filledOutput.div(fo.totalOrderOutput).times(fo.totalOrderOutputFee);
 | 
			
		||||
        const filledInput = solveForInputFillAmount(
 | 
			
		||||
            remainingInput,
 | 
			
		||||
            fo.totalOrderInput,
 | 
			
		||||
            fo.totalOrderInput,
 | 
			
		||||
            fo.totalOrderInputFee,
 | 
			
		||||
        );
 | 
			
		||||
        const filledOutput = fo.totalOrderOutput.times(filledInput.div(fo.totalOrderInput));
 | 
			
		||||
        const filledInputFee = filledInput.div(fo.totalOrderInput).times(fo.totalOrderInputFee);
 | 
			
		||||
        const filledOutputFee = filledOutput.div(fo.totalOrderOutput).times(fo.totalOrderOutputFee);
 | 
			
		||||
 | 
			
		||||
        result.inputBySource[source] = result.inputBySource[source].plus(filledInput);
 | 
			
		||||
        result.input = result.input.plus(filledInput);
 | 
			
		||||
        result.output = result.output.plus(filledOutput);
 | 
			
		||||
        result.inputFee = result.inputFee.plus(filledInputFee);
 | 
			
		||||
        result.outputFee = result.outputFee.plus(filledOutputFee);
 | 
			
		||||
        remainingInput = remainingInput.minus(filledInput.plus(filledInputFee));
 | 
			
		||||
 | 
			
		||||
                result.inputBySource[source] = result.inputBySource[source].plus(filledInput);
 | 
			
		||||
                result.input = result.input.plus(filledInput);
 | 
			
		||||
                result.output = result.output.plus(filledOutput);
 | 
			
		||||
                result.inputFee = result.inputFee.plus(filledInputFee);
 | 
			
		||||
                result.outputFee = result.outputFee.plus(filledOutputFee);
 | 
			
		||||
                remainingInput = remainingInput.minus(filledInput.plus(filledInputFee));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // NOTE: V4 Limit orders have Protocol fees
 | 
			
		||||
        const protocolFee = hasProtocolFee(fo.order) ? protocolFeePerFillOrder : ZERO_AMOUNT;
 | 
			
		||||
        result.protocolFee = result.protocolFee.plus(protocolFee);
 | 
			
		||||
@@ -191,7 +172,7 @@ export function fillQuoteOrders(
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function hasProtocolFee(o: OptimizedMarketOrder): boolean {
 | 
			
		||||
function hasProtocolFee(o: SwapQuoteOrder): boolean {
 | 
			
		||||
    return o.type === FillQuoteTransformerOrderType.Limit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -234,13 +215,7 @@ function createBestCaseFillOrderCalls(quoteInfo: QuoteFillInfo): QuoteFillOrderC
 | 
			
		||||
            ? {
 | 
			
		||||
                  totalOrderInput: o.takerAmount,
 | 
			
		||||
                  totalOrderOutput: o.makerAmount,
 | 
			
		||||
                  totalOrderInputFee:
 | 
			
		||||
                      o.type === FillQuoteTransformerOrderType.Limit
 | 
			
		||||
                          ? getNativeAdjustedTakerFeeAmount(
 | 
			
		||||
                                (o.fillData as NativeLimitOrderFillData).order,
 | 
			
		||||
                                o.takerAmount,
 | 
			
		||||
                            )
 | 
			
		||||
                          : ZERO_AMOUNT,
 | 
			
		||||
                  totalOrderInputFee: ZERO_AMOUNT, // Limit orders not supported atm
 | 
			
		||||
                  totalOrderOutputFee: ZERO_AMOUNT, // makerToken fees are not supported in v4 (sell output)
 | 
			
		||||
              }
 | 
			
		||||
            : // Buy
 | 
			
		||||
@@ -248,13 +223,7 @@ function createBestCaseFillOrderCalls(quoteInfo: QuoteFillInfo): QuoteFillOrderC
 | 
			
		||||
                  totalOrderInput: o.makerAmount,
 | 
			
		||||
                  totalOrderOutput: o.takerAmount,
 | 
			
		||||
                  totalOrderInputFee: ZERO_AMOUNT, // makerToken fees are not supported in v4 (buy input)
 | 
			
		||||
                  totalOrderOutputFee:
 | 
			
		||||
                      o.type === FillQuoteTransformerOrderType.Limit
 | 
			
		||||
                          ? getNativeAdjustedTakerFeeAmount(
 | 
			
		||||
                                (o.fillData as NativeLimitOrderFillData).order,
 | 
			
		||||
                                o.takerAmount,
 | 
			
		||||
                            )
 | 
			
		||||
                          : ZERO_AMOUNT,
 | 
			
		||||
                  totalOrderOutputFee: ZERO_AMOUNT, // Limit orders not supported atm
 | 
			
		||||
              }),
 | 
			
		||||
    }));
 | 
			
		||||
}
 | 
			
		||||
@@ -314,11 +283,10 @@ function fromIntermediateQuoteFillResult(ir: IntermediateQuoteFillResult, quoteI
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getTotalGasUsedByFills(fills: OptimizedMarketOrder[], gasSchedule: FeeSchedule): number {
 | 
			
		||||
function getTotalGasUsedByFills(fills: SwapQuoteOrder[]): number {
 | 
			
		||||
    let gasUsed = 0;
 | 
			
		||||
    for (const f of fills) {
 | 
			
		||||
        const fee = gasSchedule[f.source] === undefined ? 0 : gasSchedule[f.source]!(f.fillData);
 | 
			
		||||
        gasUsed += new BigNumber(fee).toNumber();
 | 
			
		||||
        gasUsed += f.gasCost;
 | 
			
		||||
    }
 | 
			
		||||
    return gasUsed;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,100 +1,19 @@
 | 
			
		||||
import { CommonOrderFields, FillQuoteTransformerOrderType, LimitOrderFields } from '@0x/protocol-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { Web3Wrapper } from '@0x/web3-wrapper';
 | 
			
		||||
import { ChainId } from '@0x/contract-addresses';
 | 
			
		||||
 | 
			
		||||
import { constants } from '../constants';
 | 
			
		||||
import { NativeOrderFillableAmountFields, SignedNativeOrder } from '../types';
 | 
			
		||||
 | 
			
		||||
import { ZERO_AMOUNT } from './market_operation_utils/constants';
 | 
			
		||||
 | 
			
		||||
// tslint:disable: no-unnecessary-type-assertion completed-docs
 | 
			
		||||
 | 
			
		||||
export function numberPercentageToEtherTokenAmountPercentage(percentage: number): BigNumber {
 | 
			
		||||
    return Web3Wrapper.toBaseUnitAmount(constants.ONE_AMOUNT, constants.ETHER_TOKEN_DECIMALS).multipliedBy(percentage);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getAdjustedTakerAmountFromFees<T extends LimitOrderFields>(order: T): BigNumber {
 | 
			
		||||
    return order.takerAmount.plus(order.takerTokenFeeAmount);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Given an amount of taker asset, calculate the the amount of maker asset
 | 
			
		||||
 * @param order The order
 | 
			
		||||
 * @param makerFillAmount the amount of taker asset
 | 
			
		||||
 */
 | 
			
		||||
export function getNativeAdjustedMakerFillAmount(order: CommonOrderFields, takerFillAmount: BigNumber): BigNumber {
 | 
			
		||||
    // Round down because exchange rate favors Maker
 | 
			
		||||
    const makerFillAmount = takerFillAmount
 | 
			
		||||
        .multipliedBy(order.makerAmount)
 | 
			
		||||
        .div(order.takerAmount)
 | 
			
		||||
        .integerValue(BigNumber.ROUND_FLOOR);
 | 
			
		||||
    return makerFillAmount;
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * Given an amount of maker asset, calculate the equivalent amount in taker asset
 | 
			
		||||
 * @param order The order
 | 
			
		||||
 * @param makerFillAmount the amount of maker asset
 | 
			
		||||
 */
 | 
			
		||||
export function getNativeAdjustedTakerFillAmount(order: CommonOrderFields, makerFillAmount: BigNumber): BigNumber {
 | 
			
		||||
    // Round up because exchange rate favors Maker
 | 
			
		||||
    const takerFillAmount = makerFillAmount
 | 
			
		||||
        .multipliedBy(order.takerAmount)
 | 
			
		||||
        .div(order.makerAmount)
 | 
			
		||||
        .integerValue(BigNumber.ROUND_CEIL);
 | 
			
		||||
    return takerFillAmount;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Given an amount of taker asset, calculate the fee amount required for the taker
 | 
			
		||||
 * @param order The order
 | 
			
		||||
 * @param takerFillAmount the amount of taker asset
 | 
			
		||||
 */
 | 
			
		||||
export function getNativeAdjustedTakerFeeAmount(order: LimitOrderFields, takerFillAmount: BigNumber): BigNumber {
 | 
			
		||||
    // Round down because Taker fee rate favors Taker
 | 
			
		||||
    const takerFeeAmount = takerFillAmount
 | 
			
		||||
        .multipliedBy(order.takerTokenFeeAmount)
 | 
			
		||||
        .div(order.takerAmount)
 | 
			
		||||
        .integerValue(BigNumber.ROUND_FLOOR);
 | 
			
		||||
    return takerFeeAmount;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const EMPTY_FILLABLE_AMOUNTS: NativeOrderFillableAmountFields = {
 | 
			
		||||
    fillableMakerAmount: ZERO_AMOUNT,
 | 
			
		||||
    fillableTakerAmount: ZERO_AMOUNT,
 | 
			
		||||
    fillableTakerFeeAmount: ZERO_AMOUNT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function getNativeAdjustedFillableAmountsFromTakerAmount(
 | 
			
		||||
    order: SignedNativeOrder,
 | 
			
		||||
    takerFillableAmount: BigNumber,
 | 
			
		||||
): NativeOrderFillableAmountFields {
 | 
			
		||||
    if (takerFillableAmount.isZero()) {
 | 
			
		||||
        return EMPTY_FILLABLE_AMOUNTS;
 | 
			
		||||
    }
 | 
			
		||||
// TODO(kimpers): Consolidate this implementation with the one in @0x/token-metadata
 | 
			
		||||
export function valueByChainId<T>(rest: Partial<{ [key in ChainId]: T }>, defaultValue: T): { [key in ChainId]: T } {
 | 
			
		||||
    // TODO I don't like this but iterating through enums is weird
 | 
			
		||||
    return {
 | 
			
		||||
        fillableTakerAmount: takerFillableAmount,
 | 
			
		||||
        fillableMakerAmount: getNativeAdjustedMakerFillAmount(order.order, takerFillableAmount),
 | 
			
		||||
        fillableTakerFeeAmount:
 | 
			
		||||
            order.type === FillQuoteTransformerOrderType.Limit
 | 
			
		||||
                ? getNativeAdjustedTakerFeeAmount(order.order as LimitOrderFields, takerFillableAmount)
 | 
			
		||||
                : ZERO_AMOUNT,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getNativeAdjustedFillableAmountsFromMakerAmount(
 | 
			
		||||
    order: SignedNativeOrder,
 | 
			
		||||
    makerFillableAmount: BigNumber,
 | 
			
		||||
): NativeOrderFillableAmountFields {
 | 
			
		||||
    if (makerFillableAmount.isZero()) {
 | 
			
		||||
        return EMPTY_FILLABLE_AMOUNTS;
 | 
			
		||||
    }
 | 
			
		||||
    const takerFillableAmount = getNativeAdjustedTakerFillAmount(order.order, makerFillableAmount);
 | 
			
		||||
    return {
 | 
			
		||||
        fillableMakerAmount: makerFillableAmount,
 | 
			
		||||
        fillableTakerAmount: takerFillableAmount,
 | 
			
		||||
        fillableTakerFeeAmount:
 | 
			
		||||
            order.type === FillQuoteTransformerOrderType.Limit
 | 
			
		||||
                ? getNativeAdjustedTakerFeeAmount(order.order as LimitOrderFields, takerFillableAmount)
 | 
			
		||||
                : ZERO_AMOUNT,
 | 
			
		||||
        [ChainId.Mainnet]: defaultValue,
 | 
			
		||||
        [ChainId.Ropsten]: defaultValue,
 | 
			
		||||
        [ChainId.Rinkeby]: defaultValue,
 | 
			
		||||
        [ChainId.Kovan]: defaultValue,
 | 
			
		||||
        [ChainId.Ganache]: defaultValue,
 | 
			
		||||
        [ChainId.BSC]: defaultValue,
 | 
			
		||||
        [ChainId.Polygon]: defaultValue,
 | 
			
		||||
        [ChainId.PolygonMumbai]: defaultValue,
 | 
			
		||||
        [ChainId.Avalanche]: defaultValue,
 | 
			
		||||
        [ChainId.Fantom]: defaultValue,
 | 
			
		||||
        ...(rest || {}),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,87 +5,9 @@
 | 
			
		||||
 */
 | 
			
		||||
import { ContractArtifact } from 'ethereum-types';
 | 
			
		||||
 | 
			
		||||
import * as ApproximateBuys from '../test/generated-artifacts/ApproximateBuys.json';
 | 
			
		||||
import * as BalanceChecker from '../test/generated-artifacts/BalanceChecker.json';
 | 
			
		||||
import * as BalancerSampler from '../test/generated-artifacts/BalancerSampler.json';
 | 
			
		||||
import * as BalancerV2Sampler from '../test/generated-artifacts/BalancerV2Sampler.json';
 | 
			
		||||
import * as BancorSampler from '../test/generated-artifacts/BancorSampler.json';
 | 
			
		||||
import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json';
 | 
			
		||||
import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json';
 | 
			
		||||
import * as DODOV2Sampler from '../test/generated-artifacts/DODOV2Sampler.json';
 | 
			
		||||
import * as DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquidityProvider.json';
 | 
			
		||||
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
 | 
			
		||||
import * as FakeTaker from '../test/generated-artifacts/FakeTaker.json';
 | 
			
		||||
import * as IBalancer from '../test/generated-artifacts/IBalancer.json';
 | 
			
		||||
import * as IBancor from '../test/generated-artifacts/IBancor.json';
 | 
			
		||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
 | 
			
		||||
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
 | 
			
		||||
import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json';
 | 
			
		||||
import * as IMStable from '../test/generated-artifacts/IMStable.json';
 | 
			
		||||
import * as IMultiBridge from '../test/generated-artifacts/IMultiBridge.json';
 | 
			
		||||
import * as IShell from '../test/generated-artifacts/IShell.json';
 | 
			
		||||
import * as ISmoothy from '../test/generated-artifacts/ISmoothy.json';
 | 
			
		||||
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
 | 
			
		||||
import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json';
 | 
			
		||||
import * as KyberDmmSampler from '../test/generated-artifacts/KyberDmmSampler.json';
 | 
			
		||||
import * as KyberSampler from '../test/generated-artifacts/KyberSampler.json';
 | 
			
		||||
import * as LidoSampler from '../test/generated-artifacts/LidoSampler.json';
 | 
			
		||||
import * as LiquidityProviderSampler from '../test/generated-artifacts/LiquidityProviderSampler.json';
 | 
			
		||||
import * as MakerPSMSampler from '../test/generated-artifacts/MakerPSMSampler.json';
 | 
			
		||||
import * as MooniswapSampler from '../test/generated-artifacts/MooniswapSampler.json';
 | 
			
		||||
import * as MStableSampler from '../test/generated-artifacts/MStableSampler.json';
 | 
			
		||||
import * as MultiBridgeSampler from '../test/generated-artifacts/MultiBridgeSampler.json';
 | 
			
		||||
import * as NativeOrderSampler from '../test/generated-artifacts/NativeOrderSampler.json';
 | 
			
		||||
import * as SamplerUtils from '../test/generated-artifacts/SamplerUtils.json';
 | 
			
		||||
import * as ShellSampler from '../test/generated-artifacts/ShellSampler.json';
 | 
			
		||||
import * as SmoothySampler from '../test/generated-artifacts/SmoothySampler.json';
 | 
			
		||||
import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json';
 | 
			
		||||
import * as TestNativeOrderSampler from '../test/generated-artifacts/TestNativeOrderSampler.json';
 | 
			
		||||
import * as TwoHopSampler from '../test/generated-artifacts/TwoHopSampler.json';
 | 
			
		||||
import * as UniswapSampler from '../test/generated-artifacts/UniswapSampler.json';
 | 
			
		||||
import * as UniswapV2Sampler from '../test/generated-artifacts/UniswapV2Sampler.json';
 | 
			
		||||
import * as UniswapV3Sampler from '../test/generated-artifacts/UniswapV3Sampler.json';
 | 
			
		||||
import * as UtilitySampler from '../test/generated-artifacts/UtilitySampler.json';
 | 
			
		||||
export const artifacts = {
 | 
			
		||||
    ApproximateBuys: ApproximateBuys as ContractArtifact,
 | 
			
		||||
    BalanceChecker: BalanceChecker as ContractArtifact,
 | 
			
		||||
    BalancerSampler: BalancerSampler as ContractArtifact,
 | 
			
		||||
    BalancerV2Sampler: BalancerV2Sampler as ContractArtifact,
 | 
			
		||||
    BancorSampler: BancorSampler as ContractArtifact,
 | 
			
		||||
    CurveSampler: CurveSampler as ContractArtifact,
 | 
			
		||||
    DODOSampler: DODOSampler as ContractArtifact,
 | 
			
		||||
    DODOV2Sampler: DODOV2Sampler as ContractArtifact,
 | 
			
		||||
    ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
 | 
			
		||||
    FakeTaker: FakeTaker as ContractArtifact,
 | 
			
		||||
    KyberDmmSampler: KyberDmmSampler as ContractArtifact,
 | 
			
		||||
    KyberSampler: KyberSampler as ContractArtifact,
 | 
			
		||||
    LidoSampler: LidoSampler as ContractArtifact,
 | 
			
		||||
    LiquidityProviderSampler: LiquidityProviderSampler as ContractArtifact,
 | 
			
		||||
    MStableSampler: MStableSampler as ContractArtifact,
 | 
			
		||||
    MakerPSMSampler: MakerPSMSampler as ContractArtifact,
 | 
			
		||||
    MooniswapSampler: MooniswapSampler as ContractArtifact,
 | 
			
		||||
    MultiBridgeSampler: MultiBridgeSampler as ContractArtifact,
 | 
			
		||||
    NativeOrderSampler: NativeOrderSampler as ContractArtifact,
 | 
			
		||||
    SamplerUtils: SamplerUtils as ContractArtifact,
 | 
			
		||||
    ShellSampler: ShellSampler as ContractArtifact,
 | 
			
		||||
    SmoothySampler: SmoothySampler as ContractArtifact,
 | 
			
		||||
    TwoHopSampler: TwoHopSampler as ContractArtifact,
 | 
			
		||||
    UniswapSampler: UniswapSampler as ContractArtifact,
 | 
			
		||||
    UniswapV2Sampler: UniswapV2Sampler as ContractArtifact,
 | 
			
		||||
    UniswapV3Sampler: UniswapV3Sampler as ContractArtifact,
 | 
			
		||||
    UtilitySampler: UtilitySampler as ContractArtifact,
 | 
			
		||||
    IBalancer: IBalancer as ContractArtifact,
 | 
			
		||||
    IBancor: IBancor as ContractArtifact,
 | 
			
		||||
    ICurve: ICurve as ContractArtifact,
 | 
			
		||||
    IKyberNetwork: IKyberNetwork as ContractArtifact,
 | 
			
		||||
    IMStable: IMStable as ContractArtifact,
 | 
			
		||||
    IMooniswap: IMooniswap as ContractArtifact,
 | 
			
		||||
    IMultiBridge: IMultiBridge as ContractArtifact,
 | 
			
		||||
    IShell: IShell as ContractArtifact,
 | 
			
		||||
    ISmoothy: ISmoothy as ContractArtifact,
 | 
			
		||||
    IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
 | 
			
		||||
    IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
 | 
			
		||||
    DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact,
 | 
			
		||||
    TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
 | 
			
		||||
    TestNativeOrderSampler: TestNativeOrderSampler as ContractArtifact,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -3,44 +3,5 @@
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
export * from '../test/generated-wrappers/approximate_buys';
 | 
			
		||||
export * from '../test/generated-wrappers/balance_checker';
 | 
			
		||||
export * from '../test/generated-wrappers/balancer_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/balancer_v2_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/bancor_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/curve_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/d_o_d_o_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/d_o_d_o_v2_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/dummy_liquidity_provider';
 | 
			
		||||
export * from '../test/generated-wrappers/erc20_bridge_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/fake_taker';
 | 
			
		||||
export * from '../test/generated-wrappers/i_balancer';
 | 
			
		||||
export * from '../test/generated-wrappers/i_bancor';
 | 
			
		||||
export * from '../test/generated-wrappers/i_curve';
 | 
			
		||||
export * from '../test/generated-wrappers/i_kyber_network';
 | 
			
		||||
export * from '../test/generated-wrappers/i_m_stable';
 | 
			
		||||
export * from '../test/generated-wrappers/i_mooniswap';
 | 
			
		||||
export * from '../test/generated-wrappers/i_multi_bridge';
 | 
			
		||||
export * from '../test/generated-wrappers/i_shell';
 | 
			
		||||
export * from '../test/generated-wrappers/i_smoothy';
 | 
			
		||||
export * from '../test/generated-wrappers/i_uniswap_exchange_quotes';
 | 
			
		||||
export * from '../test/generated-wrappers/i_uniswap_v2_router01';
 | 
			
		||||
export * from '../test/generated-wrappers/kyber_dmm_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/kyber_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/lido_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/liquidity_provider_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/m_stable_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/maker_p_s_m_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/mooniswap_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/multi_bridge_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/native_order_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/sampler_utils';
 | 
			
		||||
export * from '../test/generated-wrappers/shell_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/smoothy_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/test_erc20_bridge_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/test_native_order_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/two_hop_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/uniswap_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/uniswap_v2_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/uniswap_v3_sampler';
 | 
			
		||||
export * from '../test/generated-wrappers/utility_sampler';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,51 +1,12 @@
 | 
			
		||||
{
 | 
			
		||||
    "extends": "../../tsconfig",
 | 
			
		||||
    "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
 | 
			
		||||
    "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
 | 
			
		||||
    "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true, "lib": ["es2019"] },
 | 
			
		||||
    "include": ["./src/**/*", "./generated-wrappers/**/*"],
 | 
			
		||||
    "files": [
 | 
			
		||||
        "generated-artifacts/BalanceChecker.json",
 | 
			
		||||
        "generated-artifacts/ERC20BridgeSampler.json",
 | 
			
		||||
        "generated-artifacts/FakeTaker.json",
 | 
			
		||||
        "test/generated-artifacts/ApproximateBuys.json",
 | 
			
		||||
        "test/generated-artifacts/BalanceChecker.json",
 | 
			
		||||
        "test/generated-artifacts/BalancerSampler.json",
 | 
			
		||||
        "test/generated-artifacts/BalancerV2Sampler.json",
 | 
			
		||||
        "test/generated-artifacts/BancorSampler.json",
 | 
			
		||||
        "test/generated-artifacts/CurveSampler.json",
 | 
			
		||||
        "test/generated-artifacts/DODOSampler.json",
 | 
			
		||||
        "test/generated-artifacts/DODOV2Sampler.json",
 | 
			
		||||
        "test/generated-artifacts/DummyLiquidityProvider.json",
 | 
			
		||||
        "test/generated-artifacts/ERC20BridgeSampler.json",
 | 
			
		||||
        "test/generated-artifacts/FakeTaker.json",
 | 
			
		||||
        "test/generated-artifacts/IBalancer.json",
 | 
			
		||||
        "test/generated-artifacts/IBancor.json",
 | 
			
		||||
        "test/generated-artifacts/ICurve.json",
 | 
			
		||||
        "test/generated-artifacts/IKyberNetwork.json",
 | 
			
		||||
        "test/generated-artifacts/IMStable.json",
 | 
			
		||||
        "test/generated-artifacts/IMooniswap.json",
 | 
			
		||||
        "test/generated-artifacts/IMultiBridge.json",
 | 
			
		||||
        "test/generated-artifacts/IShell.json",
 | 
			
		||||
        "test/generated-artifacts/ISmoothy.json",
 | 
			
		||||
        "test/generated-artifacts/IUniswapExchangeQuotes.json",
 | 
			
		||||
        "test/generated-artifacts/IUniswapV2Router01.json",
 | 
			
		||||
        "test/generated-artifacts/KyberDmmSampler.json",
 | 
			
		||||
        "test/generated-artifacts/KyberSampler.json",
 | 
			
		||||
        "test/generated-artifacts/LidoSampler.json",
 | 
			
		||||
        "test/generated-artifacts/LiquidityProviderSampler.json",
 | 
			
		||||
        "test/generated-artifacts/MStableSampler.json",
 | 
			
		||||
        "test/generated-artifacts/MakerPSMSampler.json",
 | 
			
		||||
        "test/generated-artifacts/MooniswapSampler.json",
 | 
			
		||||
        "test/generated-artifacts/MultiBridgeSampler.json",
 | 
			
		||||
        "test/generated-artifacts/NativeOrderSampler.json",
 | 
			
		||||
        "test/generated-artifacts/SamplerUtils.json",
 | 
			
		||||
        "test/generated-artifacts/ShellSampler.json",
 | 
			
		||||
        "test/generated-artifacts/SmoothySampler.json",
 | 
			
		||||
        "test/generated-artifacts/TestERC20BridgeSampler.json",
 | 
			
		||||
        "test/generated-artifacts/TestNativeOrderSampler.json",
 | 
			
		||||
        "test/generated-artifacts/TwoHopSampler.json",
 | 
			
		||||
        "test/generated-artifacts/UniswapSampler.json",
 | 
			
		||||
        "test/generated-artifacts/UniswapV2Sampler.json",
 | 
			
		||||
        "test/generated-artifacts/UniswapV3Sampler.json",
 | 
			
		||||
        "test/generated-artifacts/UtilitySampler.json"
 | 
			
		||||
        "test/generated-artifacts/FakeTaker.json"
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,9 @@
 | 
			
		||||
    "extends": ["@0x/tslint-config"],
 | 
			
		||||
    "rules": {
 | 
			
		||||
        "max-file-line-count": false,
 | 
			
		||||
        "binary-expression-operand-order": false
 | 
			
		||||
        "binary-expression-operand-order": false,
 | 
			
		||||
        "no-bitwise": false,
 | 
			
		||||
        "completed-docs": false
 | 
			
		||||
    },
 | 
			
		||||
    "linterOptions": {
 | 
			
		||||
        "exclude": ["src/artifacts.ts", "test/artifacts.ts"]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										63
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								yarn.lock
									
									
									
									
									
								
							@@ -2607,6 +2607,16 @@
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@types/node" ">= 8"
 | 
			
		||||
 | 
			
		||||
"@open-rpc/client-js@^1.7.1":
 | 
			
		||||
  version "1.7.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@open-rpc/client-js/-/client-js-1.7.1.tgz#763d75c046a40f57428b861e16a9a69aaa630cb1"
 | 
			
		||||
  integrity sha512-DycSYZUGSUwFl+k9T8wLBSGA8f2hYkvS5A9AB94tBOuU8QlP468NS5ZtAxy72dF4g2WW0genwNJdfeFnHnaxXQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    isomorphic-fetch "^3.0.0"
 | 
			
		||||
    isomorphic-ws "^4.0.1"
 | 
			
		||||
    strict-event-emitter-types "^2.0.0"
 | 
			
		||||
    ws "^7.0.0"
 | 
			
		||||
 | 
			
		||||
"@sindresorhus/is@^0.14.0":
 | 
			
		||||
  version "0.14.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
 | 
			
		||||
@@ -3263,18 +3273,21 @@ aws4@^1.8.0:
 | 
			
		||||
  version "1.10.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428"
 | 
			
		||||
 | 
			
		||||
axios-mock-adapter@^1.19.0:
 | 
			
		||||
  version "1.19.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.19.0.tgz#9d72e321a6c5418e1eff067aa99761a86c5188a4"
 | 
			
		||||
axios-mock-adapter@^1.20.0:
 | 
			
		||||
  version "1.20.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.20.0.tgz#21f5b4b625306f43e8c05673616719da86e20dcb"
 | 
			
		||||
  integrity sha512-shZRhTjLP0WWdcvHKf3rH3iW9deb3UdKbdnKUoHmmsnBhVXN3sjPJM6ZvQ2r/ywgvBVQrMnjrSyQab60G1sr2w==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    fast-deep-equal "^3.1.3"
 | 
			
		||||
    is-buffer "^2.0.3"
 | 
			
		||||
    is-blob "^2.1.0"
 | 
			
		||||
    is-buffer "^2.0.5"
 | 
			
		||||
 | 
			
		||||
axios@^0.21.1:
 | 
			
		||||
  version "0.21.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
 | 
			
		||||
axios@^0.24.0:
 | 
			
		||||
  version "0.24.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6"
 | 
			
		||||
  integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    follow-redirects "^1.10.0"
 | 
			
		||||
    follow-redirects "^1.14.4"
 | 
			
		||||
 | 
			
		||||
babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
 | 
			
		||||
  version "6.26.0"
 | 
			
		||||
@@ -6608,9 +6621,10 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2:
 | 
			
		||||
    inherits "^2.0.3"
 | 
			
		||||
    readable-stream "^2.3.6"
 | 
			
		||||
 | 
			
		||||
follow-redirects@^1.10.0:
 | 
			
		||||
  version "1.13.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
 | 
			
		||||
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==
 | 
			
		||||
 | 
			
		||||
for-each@~0.3.3:
 | 
			
		||||
  version "0.3.3"
 | 
			
		||||
@@ -7617,11 +7631,21 @@ is-binary-path@~2.1.0:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    binary-extensions "^2.0.0"
 | 
			
		||||
 | 
			
		||||
is-blob@^2.1.0:
 | 
			
		||||
  version "2.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/is-blob/-/is-blob-2.1.0.tgz#e36cd82c90653f1e1b930f11baf9c64216a05385"
 | 
			
		||||
  integrity sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==
 | 
			
		||||
 | 
			
		||||
is-buffer@^1.1.5:
 | 
			
		||||
  version "1.1.6"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
 | 
			
		||||
 | 
			
		||||
is-buffer@^2.0.3, is-buffer@~2.0.3:
 | 
			
		||||
is-buffer@^2.0.5:
 | 
			
		||||
  version "2.0.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
 | 
			
		||||
  integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
 | 
			
		||||
 | 
			
		||||
is-buffer@~2.0.3:
 | 
			
		||||
  version "2.0.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623"
 | 
			
		||||
 | 
			
		||||
@@ -7969,6 +7993,11 @@ isomorphic-fetch@^3.0.0:
 | 
			
		||||
    node-fetch "^2.6.1"
 | 
			
		||||
    whatwg-fetch "^3.4.1"
 | 
			
		||||
 | 
			
		||||
isomorphic-ws@^4.0.1:
 | 
			
		||||
  version "4.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc"
 | 
			
		||||
  integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==
 | 
			
		||||
 | 
			
		||||
isstream@0.1.x, isstream@~0.1.2:
 | 
			
		||||
  version "0.1.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
 | 
			
		||||
@@ -11657,6 +11686,11 @@ stream-to-pull-stream@^1.7.1:
 | 
			
		||||
    looper "^3.0.0"
 | 
			
		||||
    pull-stream "^3.2.3"
 | 
			
		||||
 | 
			
		||||
strict-event-emitter-types@^2.0.0:
 | 
			
		||||
  version "2.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz#05e15549cb4da1694478a53543e4e2f4abcf277f"
 | 
			
		||||
  integrity sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==
 | 
			
		||||
 | 
			
		||||
strict-uri-encode@^1.0.0:
 | 
			
		||||
  version "1.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
 | 
			
		||||
@@ -13565,6 +13599,11 @@ ws@^5.1.1:
 | 
			
		||||
  dependencies:
 | 
			
		||||
    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==
 | 
			
		||||
 | 
			
		||||
wsrun@^5.2.4:
 | 
			
		||||
  version "5.2.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/wsrun/-/wsrun-5.2.4.tgz#6eb6c3ccd3327721a8df073a5e3578fb0dea494e"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user